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

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


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

developers:tutorial:crsselection

Выбор объектов на поперечном профиле

Поперечные профили являются экземплярами класса Section. Получение списка поперечных профилей осуществляется через свойство Sections класса Corridor (подробнее о получении Corridor можно узнать из раздела руководства Выбор модели подобъекта и преобразование координат). Состояние Section определяется следующими свойствами:

  • ConstructionId - Идентификатор проектной конструкции
  • SectionLine - Контур сечения ЦММ, на которые ссылается подобъект. Статический или динамический, в зависимости от состояния свойства StaticEg
  • Selected - признак выбора поперечного профиля для последующего экспорта в чертёж
  • StaticEg - Статическая существующая земля. Если статическая земля не содержит узлов, то поперечный профиль становится динамическим
  • Station - Расстояние от начала трассы до створа поперечного профиля

Поиск поперечного профиля по пикетажу

Найти поперечный профиль по его пикетажу можно воспользовавшись следующей конструкцией:

...
    var corridor = alignment.Corridor;
    var sections = corridor.Sections; //список поперечных профилей
    var pkPlus = "1+00.00"; //пикетаж поперечного профиля
    double sta;
    if (!alignment.Stationing.TryStringToStation(pkPlus, out sta)) return;
    if (!sections.IsExist(sta)) return;
    var sectionIndex = sections.GetIndex(sta); //индекс поперечного профиля в списке поперечных профилей
    var section = sections[sectionIndex]; //поперечный профиль
...

Контекст конструирования поперечного профиля

Section не содержит в себе проектную конструкцию. В программном комплексе Топоматик Робур проектная конструкция представлена в виде контекста конструирования поперечного профиля (CrsDesignContext), который может содержать в себе различные элементы построения проектного контура поперечного профиля. Все элементы контекста являются наследниками CrsComponent. Получить доступ к контексту можно двумя способами:

  1. По индексу поперечного профиля с помощью свойства Item[Int32] класса Corridor.
  2. По расстоянию от начала трассы до створа поперечного профиля с помощью метода CreateDesignContext() класса Corridor. В этом случае контекст создаётся даже если поперечного профиля нет в списке поперечных профилей.

Базовые элементы контекста конструирования поперечного профиля:

Подготовка модуля

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

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

  • Topomatic.Alg.dll - базовые классы подобъектов
  • Topomatic.Alg.Model.dll - возможность использования класса AlignmentActivityManager для получения индекса текущего поперечного профиля
  • Topomatic.Cad.Foundation.dll - базовые математические типы и операции
  • Topomatic.Cad.View.dll - элемент управления для отображения слоёв моделей
  • Topomatic.Controls.dll - возможность использования нативного диалогового окна программного комплекса Топоматик Робур (Класс MessageDlg). Данная библиотека не является обязательной, но она требуется для работоспособности кода примеров приведённых далее.
  • Topomatic.Crs.dll - базовые классы поперечных профилей

Выбор элементов контекста конструирования поперечного профиля на экране осуществляется с помощью методов статического класса CadCursors. Подробнее о работе с классом CadCursors можно узнать в разделе руководства "Выбор элемента и ввод через курсор".

Выбор узлов конструкции поперечного профиля по коду

В этом примере мы выделим узлы конструкции поперечника с введённым пользователем кодом.

Сперва определим активную модель объекта аналогично тому, как это сделано в разделе руководства Редактирование плана и профиля в подразделе Подготовка модуля. Далее предложим пользователю ввести код узла с помощью статического класса CadCursors и его метода GetInteger(). Получим указатель на набор объектов нашего CadView c помощью свойства SelectionSet и отфильтруем объекты на поперечном профиле так, чтобы в выбор были помещены только узлы с заданным кодом.

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

...
    [cmd("select_construction_nodes_by_code")]
    private void SelectConstructionNodesByCode()
    {
        //Получаем модель текущей трассы. Если текущей является не трасса, то активируется последняя активная трасса
        Alignment alignment;
        using (var receiver = ActiveAlignmentReciver<Alignment>.CreateReciver(false))
        {
            alignment = receiver.Alignment;
            if (alignment == null)
            {
                MessageDlg.Show("Необходимо сделать трассу активной.", MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
                return;
            }
            var cadview = CadView;
            if (cadview == null) return;
 
            // Выбор точек по коду
            var code = 0;
            var getPointRes = CadCursors.GetInteger(cadview, ref code, "Введите код точки:");
            if (getPointRes == GetPointResult.Cancel) return;
 
            var ss = CadView.SelectionSet;
            ss.Clear();
            ss.SelectAll();
            ss.FilterSelected(o =>
            {
                var wrapper = o as CrsDesignEntityWrapper;
                if (wrapper == null) return false;
 
                var node = wrapper.Component as CrsNode;
                if (node == null) return false;
 
                return node.Code.Equals(code);
            });
        }
    }
...

Расчёт площади контуров конструкции поперечного профиля

В этом примере рассчитаем сумму площадей контуров конструкции поперечного с введённым пользователем кодом.

В отличии от предыдущего примера, доступ к элементам конструкции поперечного профиля мы осуществим не через набор объектов текущего видового экрана, а через контекст конструирования поперечного профиля. Для получения контекста воспользуемся свойством Item[Int32] класса Corridor. Индекс текущего поперечного профиля получим через свойство CurrentSection менеджера активности подобъекта (AlignmentActivityManager). AlignmentActivityManager получается с помощью свойства Manager класса ActiveAlignmentReciver. Получив контекст мы можем найти среди его элементов контуры при помощи метода FindContour(), передав указанный код в качестве аргумента. CrsContour не содержит информации о занимаемой им площади. Чтобы получить площадь контура следует получить список его векторов и передать этот список в качестве аргумента методу PolygonArea() статического класса CadLibrary.

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

...
    [cmd("get_construction_contours_by_code")]
    private void GetConstructionContoursByCode()
    {
        //Получаем модель текущей трассы. Если текущей является не трасса, то активируется последняя активная трасса
        Alignment alignment;
        using (var receiver = ActiveAlignmentReciver<Alignment>.CreateReciver(false))
        {
            alignment = receiver.Alignment;
            if (alignment == null)
            {
                MessageDlg.Show("Необходимо сделать трассу активной.", MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
                return;
            }
 
            //Переключаемся на вкладку поперечников и указываем код для поиска контуров
            IDocumentWindow window;
            if (!ApplicationHost.Current.ActiveProject.TryGetWindow(Consts.CrossWindow, out window)) return;
            window.Activate();
 
            var cadview = CadView;
            if (cadview == null) return;
 
            var code = 0;
            var getPointRes = CadCursors.GetInteger(cadview, ref code, "Введите код контура:");
            if (getPointRes == GetPointResult.Cancel) return;
 
            // Получение контуров по коду и расчёт их площади
            var corridor = alignment.Corridor;
            var index = receiver.Manager.CurrentSection;
            var context = corridor[index];
            if (context == null) return;
 
            var contours = context.FindContour(code);
            if (contours == null || !contours.Any())
            {
                MessageDlg.Show($"Контуры с кодом {code} не найдены.");
                return;
            }
 
            var commonArea = 0.0;
            foreach (CrsContour contour in contours)
                commonArea += CadLibrary.PolygonArea(contour.AsVectorList());
 
            MessageDlg.Show($"Общая площадь контуров с кодом {code} = {ValueConverter.AreaToStr(commonArea)}");
        }
    }
...

Расчёт объёма насыпи и выемки поперечного профиля

В этом примере определим величину объёма насыпи и выемки на поперечном профиле. За величину объёма примем площадь пресечения контура чёрной земли и контура проектной конструкции поперечного профиля.

Аналогично предыдущему примеру, получим контекст конструирования поперечного профиля. Далее из контекста получим контур поверхности земли и контур проектной линии с помощью методов GetEgContour() и GetRedLineContour() соответственно. Полученные контуры представим в виде списка двумерных векторов (Vector2D), для дальнейшей возможности рассчитать их площадь. Для расчёта площади пересечения, контуры необходимо достроить. Если требуется рассчитать площадь насыпи, в контур поверхности земли добавим два новых узла располагающиеся на 100 метров выше относительно крайних вершин контура. Контур проектной линии достроим аналогично контуру поверхности земли, но новые узлы расположим на 100 метров ниже. Величина смещения 100 метров взята в качестве примера. Важно, чтобы сегменты контура не пересекали этот контур при замыкании. Если требуется рассчитать площадь выемки, то нужно достроить контуры таким же образом, но в противоположном направлении. После того, как контур поверхности земли и контур проектной линии достроены, определим контуры их пересечения с помощью метода Intersection() класса PolygonOperation. Для подсчёта суммы площадей контуров пересечения следует воспользоваться методом PolygonArea() статического класса CadLibrary.

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

...
    [cmd("calculate_construction_contours_intersection")]
    private void CalculateConstructionContoursIntersection()
    {
        //Получаем модель текущей трассы. Если текущей является не трасса, то активируется последняя активная трасса
        Alignment alignment;
        using (var receiver = ActiveAlignmentReciver<Alignment>.CreateReciver(false))
        {
            alignment = receiver.Alignment;
            if (alignment == null)
            {
                MessageDlg.Show("Необходимо сделать трассу активной.", MessageBoxButtons.OK,
                    MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
                return;
            }
 
            var cadview = CadView;
            if (cadview == null) return;
 
            //Получаем контуры поверхности земли и проектной линии и указываем тип рассчёта
            var corridor = alignment.Corridor;
 
            var index = receiver.Manager.CurrentSection;
            var context = corridor[index];
            if (context == null) return;
 
            var eg = context.GetEgContour().AsVectorList();
            if (eg == null || eg.Count == 0)
            {
                MessageDlg.Show("Поверхность земли отсутствует.", MessageBoxButtons.OK, MessageBoxIcon.Information,
                    MessageBoxDefaultButton.Button1);
                return;
            }
 
            var red = context.GetRedLineContour().AsVectorList();
            if (red == null || red.Count == 0)
            {
                MessageDlg.Show("Проектная линия отсутствует.", MessageBoxButtons.OK, MessageBoxIcon.Information,
                    MessageBoxDefaultButton.Button1);
                return;
            }
 
            var userSelect = "Насыпи";
            if (!CadCursors.GetUserSelect(cadview, ref userSelect, null, "Рассчитать площадь: ", "Насыпи",
                "Выемки")) return;
 
            //Рассчитываем площадь пересечения
            var area = 0.0;
            if (userSelect.Equals("Насыпи", StringComparison.OrdinalIgnoreCase))
            {
                eg.Add(eg[eg.Count - 1] + new Vector2D(0.0, 100.0));
                eg.Add(eg[0] + new Vector2D(0.0, 100.0));
 
                red.Add(red[red.Count - 1] + new Vector2D(0.0, -100.0));
                red.Add(red[0] + new Vector2D(0.0, -100.0));
            }
            else
            {
                eg.Add(eg[eg.Count - 1] + new Vector2D(0.0, -100.0));
                eg.Add(eg[0] + new Vector2D(0.0, -100.0));
 
                red.Add(red[red.Count - 1] + new Vector2D(0.0, 100.0));
                red.Add(red[0] + new Vector2D(0.0, 100.0));
            }
 
            var intersections = new PolygonOperation().Intersection(eg, red);
            foreach (var intersection in intersections)
                area += CadLibrary.PolygonArea(intersection);
 
            MessageDlg.Show($"Площадь {userSelect.ToLower()}: {ValueConverter.AreaToStr(area)}");
        }
    }
...

Теперь необходимо сформировать наш файл .plugin. Заполните его следующим образом.

{
  "assemblies": {
    "TutorialSelectCrossectionElements": {
      "assembly": "TutorialSelectCrossectionElements.dll, TutorialSelectCrossectionElements.ModulePluginHost"
    }
  },
 
  "actions": {
    "id_select_construction_nodes_by_code": {
      "cmd": "select_construction_nodes_by_code",
      "title": "Выделить точки конструкции поперечника по коду"
    },
    "id_get_construction_contours_by_code": {
      "cmd": "get_construction_contours_by_code",
      "title": "Рассчитать площадь контуров конструкции поперечника по коду"
    },
    "id_calculate_construction_contours_intersection": {
      "cmd": "calculate_construction_contours_intersection",
      "title": "Рассчитать площадь насыпи/выемки на поперечнике"
    }
  },
 
  "menubars": {
    "rbproj": {
      "items": [
        {
          "id": "tutorial_menu",
          "title": "Tutorial",
          "items": [
            "id_select_construction_nodes_by_code",
            "id_get_construction_contours_by_code",
            "id_calculate_construction_contours_intersection"
          ]
        }
      ]
    }
  }
}

Результатом запуска проекта будет появление в главном меню пункта «Tutorial», с подпунктами, которые будут работать в соответствии с описанными выше алгоритмами.

Исходный код примера расположен в проекте «TutorialSelectCrossectionElements».
developers/tutorial/crsselection.txt · Последние изменения: 2022/08/12 08:51 — proxor