====== Добавление и редактирование элементов поверхности ======
==== Добавление и редактирование точек поверхности ====
Одним из основных элементов [[road:work_with_cmm:create_and_edit_surface_new:basic_terms_and_definition_new|поверхности]] является [[road:work_with_cmm:create_and_edit_surface_new:notion_dots_new|съёмочная точка]] типа [[developers:references:topomatic.sfc.surfacepoint|SurfacePoint]]. Так как [[developers:references:topomatic.sfc.surfacepoint|SurfacePoint]] является структурой, а не классом, редактирование [[developers:references:topomatic.sfc.surfacepoint|SurfacePoint]] напрямую не приведёт к желаемому результату. Добавления новых и редактирование существующих [[road:work_with_cmm:create_and_edit_surface_new:notion_dots_new|точек]] осуществляется с помощью специального класса [[developers:references:topomatic.sfc.pointeditor|PointEditor]].
[[developers:references:topomatic.sfc.pointeditor|PointEditor]] позволяет осуществлять следующие операции с [[road:work_with_cmm:create_and_edit_surface_new:notion_dots_new|точками поверхности]]:
* [[developers:references:topomatic.sfc.pointeditor.add_topomatic.sfc.surfacepoint|PointEditor.Add()]] - добавление новой [[road:work_with_cmm:create_and_edit_surface_new:notion_dots_new|точки]] в [[road:work_with_cmm:create_and_edit_surface_new:basic_terms_and_definition_new|поверхность]]
* [[developers:references:topomatic.sfc.pointeditor.remove_system.int32|PointEditor.Remove()]] - удаление существующей [[road:work_with_cmm:create_and_edit_surface_new:notion_dots_new|точки]] из [[road:work_with_cmm:create_and_edit_surface_new:basic_terms_and_definition_new|поверхности]]
* [[developers:references:topomatic.sfc.pointeditor.setvalue_system.int32_topomatic.sfc.surfacepoint|PointEditor.SetValue()]] - замена существующей [[road:work_with_cmm:create_and_edit_surface_new:notion_dots_new|точки поверхности]] новой
* [[developers:references:topomatic.sfc.pointeditor.setvertex_system.int32_topomatic.cad.foundation.vector3d|PointEditor.SetVertex()]] - изменение расположения существующей [[road:work_with_cmm:create_and_edit_surface_new:notion_dots_new|точки поверхности]] в пространстве
* [[developers:references:topomatic.sfc.pointeditor.transform_system.collections.generic.ienumerable_1_topomatic.cad.foundation.matrix|PointEditor.Transform()]] - изменение расположения существующих [[road:work_with_cmm:create_and_edit_surface_new:notion_dots_new|точек поверхности]] в пространстве с помощью матрицы преобразования
==== Добавление и редактирование структурных линий ====
Для добавления [[road:work_with_cmm:create_and_edit_surface_new:notion_structural_lines_new|структурных линий]] помощи специальных классов не требуется. Их можно добавлять напрямую в [[developers:references:topomatic.sfc.surface.structurelines|коллекцию структурных линий (Surface.StructureLines)]] нужной поверхности. Аналогично с [[developers:references:topomatic.sfc.pointeditor|PointEditor]], методы [[developers:references:topomatic.sfc.structurelines.add_topomatic.sfc.structureline|StructureLines.Add()]] и [[developers:references:topomatic.sfc.structurelines.remove_topomatic.sfc.structureline|StructureLines.Remove()]] дают возможность добавить или удалить структурную линию соответственно. Для удаления структурной линии по её индексу, можно воспользоваться методом [[developers:references:topomatic.sfc.structurelines.removeat_system.int32|StructureLines.RemoveAt()]].
Редактировать [[road:work_with_cmm:create_and_edit_surface_new:notion_structural_lines_new|структурные линии]] следует напрямую. Например, если мы хотим добавить существующую [[road:work_with_cmm:create_and_edit_surface_new:notion_dots_new|точку поверхности]] в [[road:work_with_cmm:create_and_edit_surface_new:notion_structural_lines_new|структурную линию]], нужно именно у неё вызвать метод [[developers:references:topomatic.sfc.structureline.add_system.int32|Add()]].
[[road:work_with_cmm:create_and_edit_surface_new:notion_structural_lines_new|Структурная линия]] всегда опирается на [[developers:references:topomatic.sfc.surfacepoint|точки поверхности]] и не может существовать без них.
==== Настройка проекта Visual Studio ====
Прежде чем приступить работе с элементами поверхности, создайте и настройте новый [[developers:tutorial:module|модуль]] для подключения к программному комплексу [[http://www.topomatic.ru|Топоматик Робур]].
С помощью диалогового окна Менеджер ссылок добавьте ссылки на следующие библиотеки:
* [[developers:references:topomatic.cad.foundation|Topomatic.Cad.Foundation.dll]] - базовые математические типы и операции
* [[developers:references:topomatic.cad.view|Topomatic.Cad.View.dll]] - элемент управления для отображения слоёв моделей
* [[developers:references:topomatic.dwg|Topomatic.Dwg.dll]] - примитивы и модель чертежа
* [[developers:references:topomatic.sfc|Topomatic.Sfc.dll]] - поверхность
* [[developers:references:topomatic.sfc.layer|Topomatic.Sfc.Layer.dll]] - слой поверхности
* [[developers:references:topomatic.foundationclasses|Topomatic.FoundationClasses]] - базовые классы программного комплекса [[http://www.topomatic.ru|Топоматик Робур]].
* [[developers:references:topomatic.smt|Topomatic.Smt]] - семантика
В следующих примерах используются классы и методы предыдущего урока, в котором рассматривается процесс [[developers:tutorial:sfcselection|выделения элементов поверхности]].
===== Добавление элементов поверхности =====
В этом примере мы выберем замкнутую [[road:work_with_cmm:create_and_edit_surface_new:notion_structural_lines_new|структурную линию]] и на указанном расстоянии от неё построим новую с учётом приращения высоты.
Для этого нам потребуются координаты точек эквидистанты существующей [[road:work_with_cmm:create_and_edit_surface_new:notion_structural_lines_new|структурной линии]]. Далее мы рассчитаем новое значение высоты этих точек и на основе полученных координат создадим новые [[developers:references:topomatic.sfc.surfacepoint|точки поверхности]]. Вновь созданные [[developers:references:topomatic.sfc.surfacepoint|точки поверхности]] станут основой для создания новой [[road:work_with_cmm:create_and_edit_surface_new:notion_structural_lines_new|структурной линии]].
Эквидистанта для новой [[road:work_with_cmm:create_and_edit_surface_new:notion_structural_lines_new|структурной линии]] должна рассчитываться относительно удалённости курсора от выбранной [[road:work_with_cmm:create_and_edit_surface_new:notion_structural_lines_new|структурной линии]]. Чтобы получить это значение, необходимо воспользоваться методом [[developers:references:b91330957111b48e6dd7fd9cf6e05eba|CadLibrary.PosToPolylineStaOffset()]]. В качестве аргументов, метод принимает список координат полилинии типа [[developers:references:topomatic.cad.foundation.vector2d|Vector2D]], координаты курсора типа [[developers:references:topomatic.cad.foundation.vector2d|Vector2D]] и записывает рассчитанные значения в принимаемые переменные ''offset'' и ''station'' типа [[https://docs.microsoft.com/ru-ru/dotnet/api/system.double?view=net-6.0|double]] с модификатором [[https://docs.microsoft.com/ru-ru/dotnet/csharp/language-reference/keywords/out-parameter-modifier|out]]. ''offset'' - кратчайшее расстояние от курсора до полилинии, а ''station'' - длина части полилинии от её первой точки до точки в которой был определён ''offset''.
Для наглядности будущего положения новой структурной линии мы воспользуемся [[developers:tutorial:dynamicrender|динамической отрисовкой]] примитива.
В теле программного модуля объявите команду, и декорируйте её атрибутом «cmd». Команда «create_hill_or_pit» предложит пользователю выбрать замкнутую структурную линию и приращение высоты. Результатом действия станет сооружение насыпи или котлована в зависимости от значений указанных пользователем.
{
...
[cmd("create_hill_or_pit")]
private void CreateHillOrPit()
{
//Находим активный SurfaceLayer
var cadview = CadView;
if (cadview == null) return;
var layer = SurfaceLayer.GetSurfaceLayer(cadview);
if (layer == null) return;
var sfc = layer.Surface;
//Выбираем структурную линию и получаем список её двумерных координат
var strLine = layer.SelectOneStructureLine(i => sfc.StructureLines[i].IsClosed,
"Выберите замкнутую структурную линию:");
if (strLine == null) return;
var poly = new List();
strLine.ToPolyline(poly);
var poly2d = poly.Select(v => v.Pos).ToList();
//Делегат для динамической отрисовки контура будущей структурной линии
DrawCursorEvent ondraw = delegate (CadPen pen, Vector3D vertex)
{
double s, o;
//находим смещение точки по линии
if (CadLibrary.PosToPolylineStaOffset(poly2d, vertex.Pos, out o, out s))
{
var offs_line = new List();
poly.Offset(o, offs_line);
//Создаём примитив и рисуем его
var entity = new DwgPolyline();
entity.Prepare(sfc.Situation);
foreach (var v in offs_line)
{
entity.Add(new BugleVector2D(v.Pos));
}
entity.Color = CadColor.Green;
PaintEntityEventArgs.PaintEntity(entity, pen);
}
};
//Подписываемся на событие динамической отрисовки примитивов
cadview.DynamicDraw += ondraw;
Vector3D point;
GetPointResult res;
try
{
//Указываем курсором точку на плане определяющую сторону и величину смещения
//и закладываем возможность задать смещение с клавиатуры
res = CadCursors.GetPoint(cadview, out point, "Укажите смещение или:", "Задать величину смещения");
}
finally
{
//Отписываемся от события, так как динамическая отрисовка нам больше не требуется
cadview.DynamicDraw -= ondraw;
}
double sta;
var off = 0.0;
if (res == GetPointResult.Accept)
{
CadLibrary.PosToPolylineStaOffset(poly2d, point.Pos, out off, out sta);
}
else if (res == GetPointResult.UserCmd)
{
if (CadCursors.GetDouble(cadview, ref off, "Задайте смещение:") == GetPointResult.Cancel) return;
}
else if (res == GetPointResult.Cancel) return;
var delta = 0.0;
var incline = 0.0;
//Указываем величину приращения отметок смещённой структурной линии
//и закладываем возможность задать уклон откоса
//В случае если пользователь просто нажмёт Enter то функция вернёт UserCmd
res = CadCursors.GetDouble(cadview, ref delta, "Укажите разницу высот или:", "Задать уклон");
if (res == GetPointResult.UserCmd && cadview.LastUserCmd != "")
{
if (CadCursors.GetDouble(cadview, ref incline, "Укажите уклон:") == GetPointResult.Cancel) return;
delta = incline * Math.Abs(off);
}
else if (res == GetPointResult.Cancel) return;
//Определяем эквидистанту в соответствии с параметрами указанными пользователем
var offsetPoly = new List();
poly.Offset(off, offsetPoly);
offsetPoly.Remove(offsetPoly[offsetPoly.Count - 1]);
//Фиксируем момент начала внесения изменений в поверхность
sfc.BeginUpdate("Построить насыпь или котлован");
//Создаём точки поверхности и добавляем их в структурную линию
try
{
var offsetStrLine = new StructureLine();
var editor = new PointEditor(sfc);
foreach (var polylinePoint in offsetPoly)
{
var sfcPoint = new SurfacePoint(polylinePoint + new Vector3D(0.0, 0.0, delta));
sfcPoint.IsSituation = false;
var sfcPointIndex = editor.Add(sfcPoint);
offsetStrLine.Add(sfcPointIndex);
}
offsetStrLine.IsClosed = true;
sfc.StructureLines.Add(offsetStrLine);
}
finally
{
//Фиксируем окончание внесения изменений в поверхность
sfc.EndUpdate();
}
//Очищаем список выбранных элементов поверхности
//и сообщаем CadView о необходиомсти обновить отображение его содержимого
layer.SelectionSet.Clear();
cadview.Unlock();
cadview.Invalidate();
}
...
}
{{ :developers:tutorial:surfaceelementsedit:tutcreatestrline.png?nolink&600 |}}
===== Редактирование элементов поверхности =====
В этом примере мы рассмотрим процесс замены [[road:commons_tasks:purpose_objects_semantics:start|объекта семантики]] у [[road:work_with_cmm:create_and_edit_surface_new:notion_dots_new|точки поверхности]] и изменение значений его свойств.
Изменение семантики точки осуществляется через специальный класс [[developers:references:topomatic.sfc.surfacepointextensiveinformation|SurfacePointExtensiveInformation]], который хранит в себе подробную информацию о точке поверхности. Получить эту информацию можно с помощью метода [[developers:references:topomatic.sfc.surfacepointarray.getextensiveinformation_ref_topomatic.sfc.surfacepoint|SurfacePointArray.GetExtensiveInformation()]]. В качестве аргумента метод принимает [[road:work_with_cmm:create_and_edit_surface_new:notion_dots_new|точку поверхности]] или её индекс в [[developers:references:topomatic.sfc.surfacepointarray|массиве точек поверхности]].
Чтобы поменять [[road:commons_tasks:purpose_objects_semantics:start|семантический объект]] [[road:work_with_cmm:create_and_edit_surface_new:notion_dots_new|точки поверхности]], следует изменить значение свойства [[developers:references:topomatic.sfc.surfacepointextensiveinformation.code|SurfacePointExtensiveInformation.Code]]. В этом примере мы назначим точке объект ''Пункт государственной геодезической сети'', который имеет код ''1000''.
Состояние [[road:commons_tasks:purpose_objects_semantics:start|семантического объекта]] описывается его [[road:commons_tasks:edit_objects:start|семантическими свойствами]] и хранится в классе [[developers:references:topomatic.smt.semanticdataset|SemanticDataSet]]. Это состояние можно получить через свойство [[developers:references:topomatic.sfc.surfacepointextensiveinformation.semantic|SurfacePointExtensiveInformation.Semantic]].
[[road:commons_tasks:edit_objects:start|Семантические свойства]] являются подтипами [[developers:references:topomatic.smt.semanticpropertynode|SemanticPropertyNode]]. Среди них:
* [[developers:references:topomatic.smt.semanticdoublenode|Topomatic.Smt.SemanticDoubleNode]] - ствойство с плавающей точкой
* [[developers:references:topomatic.smt.semanticintegernode|Topomatic.Smt.SemanticIntegerNode]] - целочисленное свойство
* [[developers:references:topomatic.smt.semanticjumper|Topomatic.Smt.SemanticJumper]] - условный переключатель
* [[developers:references:topomatic.smt.semanticstringnode|Topomatic.Smt.SemanticStringNode]] - строковое свойство
Необходимое [[road:commons_tasks:edit_objects:start|семантическое свойство]] можно получить по значению его свойства [[developers:references:topomatic.smt.semanticnode.tag|SemanticNode.Tag]]. Далее, зная его тип можно присвоить ему соответствующее значение. В этом примере мы будем менять значение свойства с плавающей точкой со значением тега ''CENTER''.
{{ :developers:tutorial:surfaceelementsedit:tutsemprop.png?nolink&600 |}}
Список [[road:commons_tasks:edit_objects:start|семантических свойств]] объекта можно получить с помощью метода [[developers:references:topomatic.smt.semanticdataset.gettags_system.collections.generic.idictionary_2|SemanticDataSet.GetTags()]]. В качестве аргумента метод принимает словарь [[https://docs.microsoft.com/ru-ru/dotnet/api/system.collections.generic.dictionary-2?view=net-6.0|Dictionary]], который будет заполнен доступными значениями.
После назначения [[road:commons_tasks:purpose_objects_semantics:start|объекта семантики]] у [[road:work_with_cmm:create_and_edit_surface_new:notion_dots_new|точки поверхности]], следует вызвать метод [[developers:references:topomatic.sfc.layer.surfaceextentions.refreshpointsign|Surface.RefreshPointSign()]] для перерисовки отображения условного знака объекта.
В теле программного модуля объявите команду, и декорируйте её атрибутом «cmd». Команда «change_point_semantic_code» предложит пользователю выбрать [[road:work_with_cmm:create_and_edit_surface_new:notion_dots_new|точку поверхности]] и задать значение отметки центра. Результатом действия станет изменение [[road:commons_tasks:purpose_objects_semantics:start|семантического объекта]] [[road:work_with_cmm:create_and_edit_surface_new:notion_dots_new|точки поверхности]] и заполнение свойства ''Отметка центра'' значением указанным пользователем.
{
...
[cmd("change_point_semantic_code")]
private void ChangePointSemanticCode()
{
//Находим активный SurfaceLayer
var cadview = CadView;
if (cadview == null) return;
var layer = SurfaceLayer.GetSurfaceLayer(cadview);
if (layer == null) return;
//Выбираем точку поверхности
int ind;
var res = layer.PickOnePoint(null, out ind, "Выберите точку поверхности:");
if (res == GetPointResult.Cancel) return;
//Задаём отметку
var elev = 0.0;
res = CadCursors.GetDouble(cadview, ref elev, "Задайте отметку центра:");
if (res == GetPointResult.Cancel) return;
//Фиксируем момент начала внесения изменений в поверхность
var sfc = layer.Surface;
sfc.BeginUpdate("Преобразование точки поверхности в пункт гос. геод. сети");
try
{
//Задаём точке код объекта и присваиваем значение свойству
var info = sfc.Points.GetExtensiveInformation(ind);
info.Code = 1000;
var tags = new Dictionary();
info.Semantic.GetStringTags(tags);
if (tags.ContainsKey("CENTER")) info.Semantic["CENTER"] = elev;
sfc.RefreshPointSign(info);
}
finally
{
//Фиксируем окончание внесения изменений в поверхность
sfc.EndUpdate();
}
//Очищаем список выбранных элементов поверхности
//и сообщаем CadView о необходиомсти обновить отображение его содержимого
layer.SelectionSet.Clear();
cadview.Unlock();
cadview.Invalidate();
}
...
}
{{ :developers:tutorial:surfaceelementsedit:tutchangepointsemantic.png?nolink&600 |}}
Теперь необходимо сформировать наш файл .plugin. Заполните его следующим образом.
{
"assemblies": {
"TutorialEditSurfaceElements": {
"assembly": "TutorialEditSurfaceElements.dll, TutorialEditSurfaceElements.ModulePluginHost"
}
},
"actions": {
"id_create_hill_or_pit": {
"cmd": "create_hill_or_pit",
"title": "Построить насыпь или котлован"
},
"id_change_point_semantic_code": {
"cmd": "change_point_semantic_code",
"title": "Преобразование точки поверхности в пункт гос. геод. сети"
}
},
"menubars": {
"rbproj": {
"items": [
{
"id": "tutorial_menu",
"title": "Tutorial",
"items": [
"id_create_hill_or_pit",
"id_change_point_semantic_code"
]
}
]
}
}
}
Результатом запуска проекта будет появление в главном меню пункта «Tutorial», с подпунктами, которые будут работать в соответствии с описанными выше алгоритмами.
[[developers:tutorial:tutorialcode|Исходный код]] примера расположен в проекте **"TutorialEditSurfaceElements"**.