//функция срабатывающая при объявлении бродкаста "generate_visualization_map" //подписка на бродкаст осуществляется в plugin-файле в разделе "broadcasts" [cmd("tutorial_generate_visualization")] private void GenerateVisualization(CreateVisualizationEventArgs args) { // проверяем слой на соответствие типу слоя нашей модели if (args.Layer is ModelLayer) { GenerateModelVisualization(args); args.Handled = true; } } /// /// Формирование элементов информационной модели на основе данных полученных из модели /// и добавление их в информационную модель /// /// 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(); 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; }