Здесь показаны различия между двумя версиями данной страницы.
Предыдущая версия справа и слева Предыдущая версия Следующая версия | Предыдущая версия | ||
developers:tutorial:modelviewexport [2022/12/13 12:31] proxor |
developers:tutorial:modelviewexport [2023/01/10 11:12] (текущий) proxor [Экспорт объектов в сводную ИМ] |
||
---|---|---|---|
Строка 1: | Строка 1: | ||
- | ====== Экспорт чертежа и элементов информационной модели ====== | + | ====== Экспорт чертежа и объектов информационной модели ====== |
- | Программный комплекс Топоматик Робур предоставляет пользователю возможность экспортировать плоские чертежи, а также генерировать сводную информационную модель (ИМ). В этом примере мы сформируем примитивы на основе данных нашей модели и поместим их в экспортируемый плоский чертёж. Также мы сформируем элементы ИМ на основе данных нашей модели и поместим их в экспортируемую сводную модель. | + | Программный комплекс Топоматик Робур предоставляет пользователю возможность управления формированием чертежей плана и сводной модели. Для этого необходимо реализовать поддержку бродкастов: |
+ | - "generate_planchet" - для формирования чертежа плана | ||
+ | - "generate_visualization_map" - для формирования сводной модели | ||
+ | В этом примере мы сформируем примитивы на основе данных нашей модели и поместим их в экспортируемый плоский чертёж. Также мы сформируем объекты на основе данных нашей модели и поместим их в экспортируемую сводную ИМ. | ||
==== Подготовка модуля ==== | ==== Подготовка модуля ==== | ||
Строка 15: | Строка 18: | ||
==== Подготовка проекта ==== | ==== Подготовка проекта ==== | ||
Добавим элементы нашей модели на план. В нашем случае это будет выглядеть так: | Добавим элементы нашей модели на план. В нашем случае это будет выглядеть так: | ||
- | {{ :developers:tutorial:createmodel:tut_export_model_views_1.png?nolink |}} | + | |
+ | {{ :developers:tutorial:createmodel:tut_export_model_views_1.png?direct |}} | ||
==== Экспорт элементов модели в плоский чертёж ==== | ==== Экспорт элементов модели в плоский чертёж ==== | ||
Для экспорта элементов пользовательской модели в плоский чертёж необходимы следующий действия: | Для экспорта элементов пользовательской модели в плоский чертёж необходимы следующий действия: | ||
- | - Создание команды добавления примитивов на чертёж | + | - Создать команду для добавления примитивов на чертёж |
- | - Подписаться на бродкаст "generate_planchet" в plugin-файле с помощью команды из пункта 1 | + | - Зарегистрировать вызов команды через бродкаст «generate_planchet» в plugin-файле |
==== Создание команды добавления примитивов на чертёж ==== | ==== Создание команды добавления примитивов на чертёж ==== | ||
- | Команда должна вызвать метод принимающий в качестве аргумента объект типа **GeneratePlanchetEventArgs**. Свойство **GeneratePlanchetEventArgs.Model** возвращает корневую область модели чертежа типа **DwgBlock**, в которую следует добавить необходимые примитивы (подклассы **DwgEntity**). | + | Команда должна вызвать метод принимающий в качестве аргумента объект типа **GeneratePlanchetEventArgs**. |
- | Модель чертежа можно получить с помощью свойства **DwgBlock.Drawing**. Прежде чем вносить изменения в чертёж мы зафиксируем его настройки методом **Drawing.PushState()** и выполним их сброс до состояния по умолчанию методом **Drawing.ResetStateDefault()**. Далее в блоке **try** внесём необходимые изменения в чертёж и в блоке **finally** вернём настройки чертежа в прежнее состояние методом **Drawing.PopState()**. | + | Свойство **GeneratePlanchetEventArgs.Layer** возвращает текущий экспортируемый слой типа **CadViewLayer**. С помощью этого свойства убедимся, что слой является слоем нашей модели. |
- | Свойство **GeneratePlanchetEventArgs.Layer** возвращает текущий экспортируемый слой типа **CadViewLayer**. С помощью этого свойства Убедимся, что слой является слоем нашей модели. | + | Свойство **GeneratePlanchetEventArgs.Model** возвращает корневую область модели чертежа типа **DwgBlock**, в которую следует добавить необходимые примитивы (подклассы **DwgEntity**). |
+ | |||
+ | Модель чертежа можно получить с помощью свойства **DwgBlock.Drawing**. Прежде чем вносить изменения в чертёж мы зафиксируем его настройки методом **Drawing.PushState()** и выполним их сброс до состояния по умолчанию методом **Drawing.ResetStateDefault()**. Далее в блоке **try** внесём необходимые изменения в чертёж и в блоке **finally** вернём настройки чертежа в прежнее состояние методом **Drawing.PopState()**. | ||
В теле программного модуля объявите команду, и декорируйте её атрибутом «cmd». | В теле программного модуля объявите команду, и декорируйте её атрибутом «cmd». | ||
Строка 120: | Строка 125: | ||
В результате работы команды "**tutorial_generate_planchet**" в экспортированном файле плоского чертежа появятся примитивы нашей модели. | В результате работы команды "**tutorial_generate_planchet**" в экспортированном файле плоского чертежа появятся примитивы нашей модели. | ||
- | {{ :developers:tutorial:createmodel:tut_export_model_views_3.png?nolink |}} | + | {{ :developers:tutorial:createmodel:tut_export_model_views_3.png?direct |}} |
- | ==== Экспорт элементов информационной модели в сводную ИМ ==== | + | ==== Экспорт объектов в сводную ИМ ==== |
- | Для экспорта элементов пользовательской модели в сводную ИМ необходимы следующий действия: | + | Для экспорта объектов пользовательской модели в сводную ИМ необходимы следующий действия: |
- | - Создание команды добавления элементов ИМ в сводную ИМ | + | - Создать команду для добавления объектов в сводную ИМ |
- | - Подписаться на бродкаст "generate_visualization_map" в plugin-файле с помощью команды из пункта 1 | + | - Зарегистрировать вызов команды через бродкаст «generate_visualization_map» в plugin-файле |
+ | ==== Создание команды добавления объектов в сводную ИМ ==== | ||
+ | Команда должна вызвать метод принимающий в качестве аргумента объект типа **CreateVisualizationEventArgs**. | ||
- | ==== Создание команды добавления ИМ в сводную ИМ ==== | + | Свойство **CreateVisualizationEventArgs.Layer** возвращает текущий экспортируемый слой типа **CadViewLayer**. По свойству Layer можно определить, какая именно модель в данный момент экспортируется. |
- | Команда должна вызвать метод принимающий в качестве аргумента объект типа **CreateVisualizationEventArgs**. Свойство **CreateVisualizationEventArgs.Model** возвращает корневую область модели чертежа типа **DwgBlock**, в которую следует добавить необходимые примитивы (подклассы **DwgEntity**). | + | |
- | Модель чертежа можно получить с помощью свойства **DwgBlock.Drawing**. Прежде чем вносить изменения в чертёж мы зафиксируем его настройки методом **Drawing.PushState()** и выполним их сброс до состояния по умолчанию методом **Drawing.ResetStateDefault()**. Далее в блоке **try** внесём необходимые изменения в чертёж и в блоке **finally** вернём настройки чертежа в прежнее состояние методом **Drawing.PopState()**. | + | Свойство **CreateVisualizationEventArgs.Map** возвращает сводную ИМ типа **VisualizationMap**, в которую следует добавить необходимые объекты. |
+ | |||
+ | Объекты ИМ объединяются в группы (**VisualizationGroup**). Каждая группа - это узел в дереве сводной модели. Текущую группу можно получить через свойство **VisualizationMap.Group**, и при необходимости переопределить её свойства через метод **VisualizationGroup.ApplayOverridedProperties()** или тип. Группы так же могут содержать в себе другие группы. Новая группа создаётся методом **VisualizationMap.BeginGroup()** и становится текущей. Метод **VisualizationGroup.EndGroup()** заканчивает работу с текущей группой и возвращает группу уровнем выше. | ||
+ | |||
+ | <note>Связку **BeginGroup() => EndGroup()** следует использовать в сочетании с блоком **try/finally**. | ||
+ | <code csharp> | ||
+ | # args - аргументы типа CreateVisualizationEventArgs | ||
+ | VisualizationMap map = args.Map; | ||
+ | map.BeginGroup("GroupName", false); | ||
+ | try | ||
+ | { | ||
+ | VisualizationGroup group = map.Group; | ||
+ | # пользовательские действия | ||
+ | } | ||
+ | finally | ||
+ | { | ||
+ | map.BeginGroup("GroupName", false); | ||
+ | } | ||
+ | </code> | ||
+ | </note> | ||
+ | |||
+ | Для добавления моделей в сводную ИМ используется метод **VisualizationMap.AddMesh()**, а для размещения добавленной модели в пространстве метод **VisualizationMap.AddInsertion()**. | ||
+ | |||
+ | === Добавление объекта в сводную модель === | ||
+ | |||
+ | Наша модель содержит в себе линейные объекты. В качестве примера для отображения на сводной модели примем, что линейный объект нашей модели это забор (**Fence**) с фиксированной высотой 3 метра. | ||
+ | |||
+ | Для каждого участка забора создадим полигональную сеть (**MeshGeometry3D**). | ||
+ | |||
+ | Через свойство **MeshGeometry3D.Groups** получим коллекцию групп сети (**MaterialGroupsCollection**) и добавим в неё группу с материалом (**MaterialGroup**). | ||
+ | |||
+ | Определим координаты вершин (**Vector3F**) и добавим их в коллекцию вершин (**Vector3dCollection**) через свойство **MeshGeometry3D.Positions**. | ||
+ | |||
+ | Определим грани (**Face**) опирающиеся на индексы вершин полигональной сети. Для каждой грани добавим в группу сети новый индекс методом **MaterialGroup.AddIndex()**. Через свойство **MeshGeometry3D.TriangleIndices** получим коллекцию треугольников (**TrianglesCollection**) и добавим в неё грани. | ||
+ | |||
+ | Создадим трёхмерную модель (**GeometryModel3D**). Получим словарь с материалами через свойство **GeometryModel3D.Materials** и добавим в него материал (**PhongMaterial**). Через свойство **GeometryModel3D.Meshes** получим словарь полигональных сетей и добавим в него вышеописанную сеть. | ||
+ | |||
+ | Сгенерируем новое имя для нашей 3D-модели методом **VisualizationMap.GenMeshName()**. Добавим нашу 3D-модель с новым именем в коллекцию моделей сводной ИМ методом **VisualizationMap.AddMesh**. | ||
+ | |||
+ | Создадим новую группу методом **VisualizationMap.BeginGroup()**. В блоке **try** добавим вставку (**GeometryInsertion**) ранее добавленной 3D-модели методом **VisualizationMap.AddInsertion**. Через свойство **VisualizationMap.Group** получим текущую группу (**VisualizationGroup**). Назначим ей тип через свойство **VisualizationGroup.Type**. Через свойство **VisualizationGroup.Properties** получим коллекцию свойств (**ImProperties**) и добавим в неё новые свойства (**ImProperty**) "Количество узлов" и "Длина". | ||
+ | |||
+ | В блоке **finally** закроем группу методом **VisualizationMap.EndGroup()**. | ||
В теле программного модуля объявите команду, и декорируйте её атрибутом «cmd». | В теле программного модуля объявите команду, и декорируйте её атрибутом «cmd». | ||
+ | <file csharp Module.cs> | ||
+ | //функция срабатывающая при объявлении бродкаста "generate_visualization_map" | ||
+ | //подписка на бродкаст осуществляется в plugin-файле в разделе "broadcasts" | ||
+ | [cmd("tutorial_generate_visualization")] | ||
+ | private void GenerateVisualization(CreateVisualizationEventArgs args) | ||
+ | { | ||
+ | // проверяем слой на соответствие типу слоя нашей модели | ||
+ | if (args.Layer is ModelLayer) | ||
+ | { | ||
+ | GenerateModelVisualization(args); | ||
+ | args.Handled = true; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /// <summary> | ||
+ | /// Формирование элементов информационной модели на основе данных полученных из модели | ||
+ | /// и добавление их в информационную модель | ||
+ | /// </summary> | ||
+ | /// <param name="args"></param> | ||
+ | private void GenerateModelVisualization(CreateVisualizationEventArgs args) | ||
+ | { | ||
+ | var fenceHeight = 3.0; // высота забора | ||
+ | var map = args.Map; // сводная модель | ||
+ | var layer = args.Layer as ModelLayer; | ||
+ | | ||
+ | // проверяем слой на видимость и наличием нашей модели | ||
+ | if (layer.Visible && layer.Model is Model model) | ||
+ | { | ||
+ | // собираем поверхности для определения высотного положения забора | ||
+ | var project = ApplicationHost.Current.ActiveProject as ModelProject; | ||
+ | var items = project.Model.GetChilds(); | ||
+ | var surfaces = new List<ISurface>(); | ||
+ | foreach (var item in items) | ||
+ | { | ||
+ | if (item.ModelType.Equals("dtm", StringComparison.OrdinalIgnoreCase) && item.Model is TerrainModel dtm) | ||
+ | { | ||
+ | var sfc = args.FetchSurfaces(dtm); | ||
+ | surfaces.Add(sfc); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | map.BeginGroup("CustomModel", false); | ||
+ | try | ||
+ | { | ||
+ | for (int i = 0; i < model.Count; i++) | ||
+ | { | ||
+ | // создаём полигональную сеть и добавляем в неё группу материалов | ||
+ | var mesh = new MeshGeometry3D(); | ||
+ | var materialGroup = new MaterialGroup { Material = "Fence_Material" }; | ||
+ | mesh.Groups.Add(materialGroup); | ||
+ | | ||
+ | // наполняем сеть вершинами и определяем грани опирающиеся на эти точки | ||
+ | var length = 0.0; //длина участка забора | ||
+ | var points = model[i]; | ||
+ | for (int j = 0; j < points.Count; j++) | ||
+ | { | ||
+ | var point = points[j]; | ||
+ | var elevation = 0.0; | ||
+ | foreach (var sfc in surfaces) | ||
+ | { | ||
+ | var z = sfc.GetElevation(point); | ||
+ | if (z.HasValue && ValueConverter.CompValues(z.Value, elevation) == 1) | ||
+ | { | ||
+ | elevation = z.Value; | ||
+ | } | ||
+ | } | ||
+ | mesh.Positions.Add(new Vector3F(new Vector3D(point, elevation))); | ||
+ | mesh.Positions.Add(new Vector3F(new Vector3D(point, elevation + fenceHeight))); | ||
+ | |||
+ | if (j < points.Count - 1) | ||
+ | { | ||
+ | var nextPoint = points[j + 1]; | ||
+ | var delta = nextPoint - point; | ||
+ | length += delta.Length; | ||
+ | |||
+ | var face1 = new Face(j * 2, (j + 1) * 2, j * 2 + 1); | ||
+ | var face2 = new Face((j + 1) * 2, (j + 1) * 2 + 1, j * 2 + 1); | ||
+ | materialGroup.AddIndex(TrimShort(mesh.TriangleIndices.Count)); | ||
+ | mesh.TriangleIndices.Add(face1); | ||
+ | materialGroup.AddIndex(TrimShort(mesh.TriangleIndices.Count)); | ||
+ | mesh.TriangleIndices.Add(face2); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // создаём 3D-модель и добавляем в неё материал | ||
+ | // добавляем сеть в 3D-модель | ||
+ | var geometry = new GeometryModel3D(); | ||
+ | if (!geometry.Materials.ContainsKey("Custom_Material")) | ||
+ | { | ||
+ | var material = new PhongMaterial(); | ||
+ | material.Diffuse = new Vector3F(0.6, 0.6, 0.6); | ||
+ | material.Shininess = 0.8f; | ||
+ | material.SpecularLevel = 0.8f; | ||
+ | geometry.Materials["Custom_Material"] = material; | ||
+ | } | ||
+ | geometry.Meshes["Fence_Mesh"] = mesh; | ||
+ | |||
+ | // добавляем 3D-модель в сводную модель, | ||
+ | // назначаем ей тип и необходимые свойства | ||
+ | var meshName = map.GenMeshName("custom_mesh"); | ||
+ | map.AddMesh(meshName, geometry); | ||
+ | map.BeginGroup("Fence", false); | ||
+ | try | ||
+ | { | ||
+ | map.AddInsertion(meshName, new Vector3D(0, 0, 0)); | ||
+ | |||
+ | var type = map.FindType("SmdxCustomFence"); | ||
+ | if (type == null) | ||
+ | { | ||
+ | var parent = map.FindType("SmdxElement"); | ||
+ | var typeDesc = new ImTypeDescriptor("SmdxCustomFence", "Пользовательский забор", parent); | ||
+ | type = map.CreateType(typeDesc); | ||
+ | } | ||
+ | |||
+ | map.Group.Type = type; | ||
+ | map.Group.Properties.Add(new ImProperty("points", "Количество узлов", points.Count)); | ||
+ | map.Group.Properties.Add(new ImProperty("length", "Длина", length)); | ||
+ | } | ||
+ | finally | ||
+ | { | ||
+ | map.EndGroup(); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | finally | ||
+ | { | ||
+ | map.EndGroup(); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | private static ushort TrimShort(int value) | ||
+ | { | ||
+ | Debug.Assert(value <= ushort.MaxValue); | ||
+ | return value > ushort.MaxValue ? ushort.MaxValue : (ushort)value; | ||
+ | } | ||
+ | </file> | ||
+ | |||
+ | Команда «**tutorial_generate_visualization**» должна выполняться в момент создания сводной модели. Для этого добавим соответствующую запись в plugin-файл в секции "**broadcast**" | ||
+ | |||
+ | <file javascript tut_export_model_views.plugin> | ||
+ | "broadcasts": { | ||
+ | "generate_visualization_map": "tutorial_generate_visualization" | ||
+ | } | ||
+ | </file> | ||
+ | |||
+ | В результате работы команды "**tutorial_generate_visualization**" в экспортированной сводной модели появятся объекты нашей модели. | ||
+ | |||
+ | {{ :developers:tutorial:createmodel:tut_export_model_views_2.png?direct |}} | ||
+ | |||
+ | <note>[[developers:tutorial:tutorialcode|Исходный код]] примера расположен в проекте **"TutorialExportModelViews"**.</note> |