====== Добавление и редактирование элементов поверхности ====== ==== Добавление и редактирование точек поверхности ==== Одним из основных элементов [[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"**.