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

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


Боковая панель

developers:tutorial:sfcedit

Добавление и редактирование элементов поверхности

Добавление и редактирование точек поверхности

Одним из основных элементов поверхности является съёмочная точка типа SurfacePoint. Так как SurfacePoint является структурой, а не классом, редактирование SurfacePoint напрямую не приведёт к желаемому результату. Добавления новых и редактирование существующих точек осуществляется с помощью специального класса PointEditor.

PointEditor позволяет осуществлять следующие операции с точками поверхности:

Добавление и редактирование структурных линий

Для добавления структурных линий помощи специальных классов не требуется. Их можно добавлять напрямую в коллекцию структурных линий (Surface.StructureLines) нужной поверхности. Аналогично с PointEditor, методы StructureLines.Add() и StructureLines.Remove() дают возможность добавить или удалить структурную линию соответственно. Для удаления структурной линии по её индексу, можно воспользоваться методом StructureLines.RemoveAt().

Редактировать структурные линии следует напрямую. Например, если мы хотим добавить существующую точку поверхности в структурную линию, нужно именно у неё вызвать метод Add().

Структурная линия всегда опирается на точки поверхности и не может существовать без них.

Настройка проекта Visual Studio

Прежде чем приступить работе с элементами поверхности, создайте и настройте новый модуль для подключения к программному комплексу Топоматик Робур.

С помощью диалогового окна Менеджер ссылок добавьте ссылки на следующие библиотеки:

В следующих примерах используются классы и методы предыдущего урока, в котором рассматривается процесс выделения элементов поверхности.

Добавление элементов поверхности

В этом примере мы выберем замкнутую структурную линию и на указанном расстоянии от неё построим новую с учётом приращения высоты.

Для этого нам потребуются координаты точек эквидистанты существующей структурной линии. Далее мы рассчитаем новое значение высоты этих точек и на основе полученных координат создадим новые точки поверхности. Вновь созданные точки поверхности станут основой для создания новой структурной линии.

Эквидистанта для новой структурной линии должна рассчитываться относительно удалённости курсора от выбранной структурной линии. Чтобы получить это значение, необходимо воспользоваться методом CadLibrary.PosToPolylineStaOffset(). В качестве аргументов, метод принимает список координат полилинии типа Vector2D, координаты курсора типа Vector2D и записывает рассчитанные значения в принимаемые переменные offset и station типа double с модификатором out. offset - кратчайшее расстояние от курсора до полилинии, а station - длина части полилинии от её первой точки до точки в которой был определён offset.

Для наглядности будущего положения новой структурной линии мы воспользуемся динамической отрисовкой примитива.

В теле программного модуля объявите команду, и декорируйте её атрибутом «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<Vector3D>();
        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<Vector3D>();
                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<Vector3D>();
        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();
    }
...
}

Редактирование элементов поверхности

В этом примере мы рассмотрим процесс замены объекта семантики у точки поверхности и изменение значений его свойств.

Изменение семантики точки осуществляется через специальный класс SurfacePointExtensiveInformation, который хранит в себе подробную информацию о точке поверхности. Получить эту информацию можно с помощью метода SurfacePointArray.GetExtensiveInformation(). В качестве аргумента метод принимает точку поверхности или её индекс в массиве точек поверхности.

Чтобы поменять семантический объект точки поверхности, следует изменить значение свойства SurfacePointExtensiveInformation.Code. В этом примере мы назначим точке объект Пункт государственной геодезической сети, который имеет код 1000.

Состояние семантического объекта описывается его семантическими свойствами и хранится в классе SemanticDataSet. Это состояние можно получить через свойство SurfacePointExtensiveInformation.Semantic.

Семантические свойства являются подтипами SemanticPropertyNode. Среди них:

Необходимое семантическое свойство можно получить по значению его свойства SemanticNode.Tag. Далее, зная его тип можно присвоить ему соответствующее значение. В этом примере мы будем менять значение свойства с плавающей точкой со значением тега CENTER.

Список семантических свойств объекта можно получить с помощью метода SemanticDataSet.GetTags(). В качестве аргумента метод принимает словарь Dictionary<string,string>, который будет заполнен доступными значениями.

После назначения объекта семантики у точки поверхности, следует вызвать метод Surface.RefreshPointSign() для перерисовки отображения условного знака объекта.

В теле программного модуля объявите команду, и декорируйте её атрибутом «cmd». Команда «change_point_semantic_code» предложит пользователю выбрать точку поверхности и задать значение отметки центра. Результатом действия станет изменение семантического объекта точки поверхности и заполнение свойства Отметка центра значением указанным пользователем.

{
...
    [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<string, string>();
            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();
    }
...
}

Теперь необходимо сформировать наш файл .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», с подпунктами, которые будут работать в соответствии с описанными выше алгоритмами.

Исходный код примера расположен в проекте «TutorialEditSurfaceElements».
developers/tutorial/sfcedit.txt · Последние изменения: 2022/04/09 18:54 — proxor