//функция срабатывающая при объявлении бродкаста "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;
}