Инструменты пользователя

Инструменты сайта


developers:tutorial:modelviewexport

Различия

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

Ссылка на это сравнение

Предыдущая версия справа и слева Предыдущая версия
Следующая версия
Предыдущая версия
developers:tutorial:modelviewexport [2022/12/13 12:02]
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**. 
 + 
 +Свойство **GeneratePlanchetEventArgs.Layer** возвращает текущий экспортируемый слой типа **CadViewLayer**. С помощью этого свойства убедимся,​ что слой является слоем нашей модели. 
 + 
 +Свойство **GeneratePlanchetEventArgs.Model** возвращает корневую область модели чертежа типа **DwgBlock**,​ в которую следует добавить необходимые примитивы (подклассы **DwgEntity**).
  
 Модель чертежа можно получить с помощью свойства **DwgBlock.Drawing**. Прежде чем вносить изменения в чертёж мы зафиксируем его настройки методом **Drawing.PushState()** и выполним их сброс до состояния по умолчанию методом **Drawing.ResetStateDefault()**. Далее в блоке **try** внесём необходимые изменения в чертёж и в блоке **finally** вернём настройки чертежа в прежнее состояние методом **Drawing.PopState()**. Модель чертежа можно получить с помощью свойства **DwgBlock.Drawing**. Прежде чем вносить изменения в чертёж мы зафиксируем его настройки методом **Drawing.PushState()** и выполним их сброс до состояния по умолчанию методом **Drawing.ResetStateDefault()**. Далее в блоке **try** внесём необходимые изменения в чертёж и в блоке **finally** вернём настройки чертежа в прежнее состояние методом **Drawing.PopState()**.
Строка 118: Строка 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-файле 
 +==== Создание команды добавления объектов в сводную ИМ ==== 
 +Команда должна вызвать метод принимающий в качестве аргумента объект типа **CreateVisualizationEventArgs**. 
 + 
 +Свойство **CreateVisualizationEventArgs.Layer** возвращает текущий экспортируемый слой типа **CadViewLayer**. По свойству Layer можно определить,​ какая именно модель в данный момент экспортируется. 
 + 
 +Свойство **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». 
 + 
 +<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 |}}
-Для экспорта элементов пользовательской модели в сводную ИМ необходимы следующий действия: +
-  - Создание команды добавления элементов ИМ в сводную ИМ +
-  - Подписаться на бродкаст "​generate_visualization_map"​ в plugin-файле с помощью команды из пункта 1+
  
 +<​note>​[[developers:​tutorial:​tutorialcode|Исходный код]] примера расположен в проекте **"​TutorialExportModelViews"​**.</​note>​
developers/tutorial/modelviewexport.1670932924.txt.gz · Последние изменения: 2022/12/13 12:02 — proxor