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

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


developers:tutorial:modelviewexport

Различия

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

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

Предыдущая версия справа и слева Предыдущая версия
Следующая версия
Предыдущая версия
developers:tutorial:modelviewexport [2022/12/13 11:54]
proxor [Создание команды добавления примитивов на чертёж]
developers:tutorial:modelviewexport [2023/01/10 11:12] (текущий)
proxor [Экспорт объектов в сводную ИМ]
Строка 1: Строка 1:
-====== Экспорт чертежа и элементов информационной модели ======+====== Экспорт чертежа и объектов информационной модели ======
  
-Программный комплекс Топоматик Робур предоставляет пользователю возможность ​экспортировать плоские чертежи, а также генерировать ​сводную информационную модель (ИМ). +Программный комплекс Топоматик Робур предоставляет пользователю возможность ​управления формированием чертежей плана и сводной модели. Для этого необходимо реализовать ​поддержку бродкастов:​ 
- +  - "​generate_planchet"​ - для ​формирования чертежа плана 
-==== Экспорт элементов информационной модели ​в сводную ИМ ==== +  - "​generate_visualization_map"​ - для ​формирования сводной модели 
-Для ​экспорта элементов пользовательской модели в сводную ИМ необходимы следующий действия: +В этом примере мы сформируем примитивы на основе данных нашей модели ​и поместим их в экспортируемый плоский чертёж. Также мы сформируем объекты ​на основе данных ​нашей модели и поместим их в экспортируемую сводную ИМ.
-  - Создание команды добавления элементов ИМ в сводную ИМ +
-  - Подписаться ​на бродкаст "​generate_visualization_map" ​в plugin-файле ​с помощью команды из пункта 1+
  
 ==== Подготовка модуля ==== ==== Подготовка модуля ====
Строка 20: Строка 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()**.
Строка 122: Строка 124:
  
 В результате работы команды "​**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 |}}
  
 +<​note>​[[developers:​tutorial:​tutorialcode|Исходный код]] примера расположен в проекте **"​TutorialExportModelViews"​**.</​note>​
developers/tutorial/modelviewexport.1670932469.txt.gz · Последние изменения: 2022/12/13 11:54 — proxor