План линии (или план трассы) является экземпляром класса PlanLine. Получить план линии можно с помощью свойства Plan класса Alignment (описание класса Alignment представлено в предыдущем разделе руководства Выбор модели подобъекта и преобразование координат). План линии представляет из себя упорядоченную коллекцию вершин плана линии (Vertex). Изменение плана линии осуществляется с помощью следующих методов класса PlanLine:
Вершина плана линии является экземпляром класса Vertex. Она представляет из себя упорядоченную коллекцию элементов вершин плана линии (VertexItem), а также хранит в себе следующую информацию о её состоянии:
Вершины плана линии создаются с помощью конструктора класса Vertex() и добавляется в PlanLine. Изменение коллекции элементов вершин осуществляется методами аналогично тем, что описаны выше для работы с планом линии.
Если вершина не содержит ни одного элемента, то она является изломом плана линии. Если вершина содержит только один элемент, то она представляет из себя однорадиусную кривую. Если элементов больше одного, то это многорадиусная кривая.
Элемент вершины плана линии являются структурами VertexItem. Непосредственное изменение VertexItem не приведёт к изменению плана линии. То есть, если вы хотите изменить существующий элемент вершины плана линии, то вам необходимо заменить существующий элемент вершины аналогично тому, как это осуществляется при работе с массивами. Рассмотрим пример изменения радиуса существующего элемента вершины плана линии.
var vertex = Alignment.Plan[i]; // получение вершины плана линии var item = vertex[j]; // получение элемента вершины плана линии item.R = 500; // изменение радиуса вершины плана линии vertex[j] = item; // замена существующего элемента вершины плана линии на изменённый
Элемент вершины плана линии создаётся с помощью конструктора VertexItem() и добавляется в Vertex. Состояние элемента вершины плана линии описывается следующими полями:
Создайте и настройте новый модуль для подключения к программному комплексу Топоматик Робур.
С помощью диалогового окна Менеджер ссылок добавьте ссылки на следующие библиотеки:
Для получения текущей модели подобъекта воспользуемся ресивером текущего подобъекта через метод CreateReciver() статического класса ActiveAlignmentReciver. Свойство Alignment ресивера вернёт Alignment текущего подобъекта или последнего активного подобъекта, если в данный момент активна модель отличная от подобъекта и активирует её.
В этом примере укажем точку на плане, определим ближайшую к этой точке вершину плана линии и если это вершина является однорадиусной кривой, то добавим к ней новый элемент вершины плана линии.
Укажем точку на плане и определим расстояние от начала трассы до этой точки аналогично тому, как описано в предыдущем разделе руководства Выбор модели подобъекта и преобразование координат. Далее определим ближайшую к этой точке вершину плана линии с помощью метода SearchNearest() класса PlanLine и если у эта вершина содержит один элемент, то добавим в неё ещё один.
В теле программного модуля объявите команду, и декорируйте её атрибутом «cmd». Команда «add_vertex_to_alignment» предложит пользователю указать точку на плане, определит ближайшую вершину плана линии и если эта вершина содержит только один элемент, то в вершину будет добавлен новый элемент.
... [cmd("add_vertex_to_alignment")] private void AddVertexToAlignment() { //Получаем модель текущей трассы. Если текущей является не трасса, то активируется последняя активная трасса 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 plan = alignment.Plan; var compound = plan.CompoundLine; //Указываем однорадиусную кривую Vector3D point; var getPointRes = CadCursors.GetPoint(cadview, out point, "Укажите однорадиусную кривую:"); if (!getPointRes) return; double station, offset; var res = compound.PosToStaOffset(point.Pos, out station, out offset); if (!res) { MessageDlg.Show("Указанная точка лежит вне плана линии.", MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1); return; } //Получаем ближайшую вершину угла к указанной точке и добавляем в неё элемент var vertex = plan.SearchNearest(station); if (vertex.Count != 1) { MessageDlg.Show("Необходимо указать однорадиусную кривую.", MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1); return; } vertex.BeginTransaction(); var result = true; try { var angle = Math.Abs(vertex.Beta); var item1 = vertex[0]; var item2 = new PlanLine.Vertex.VertexItem { R = item1.R, L2 = item1.L2, K = angle * 0.5 }; item1.L2 = 0.0; item1.K = angle * 0.5; vertex[0] = item1; vertex.Add(item2); result = PlanLineSolver.PlanVertexesValid(plan); } finally { if (result) { vertex.Commit(); } else { vertex.Rollback(); MessageDlg.Show("При разбивке кривой произошла ошибка.", MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1); } } } } ...
Профиль является наследником класса Transition. Доступ к коллекции профилей подобъекта осуществляется через свойство Transitions класса Alignment. Коллекция профилей содержит профиль по оси, а также восемь профилей слева и восемь профилей справа. Наиболее часто используемый профиль по оси трассы расположен в начале коллекции и имеет индекс 0.
Каждый профиль содержит в себе информацию о чёрном профиле, красном профиле и интерполированном профиле. Каждый из этих профилей получается с помощью соответствующего свойства класса Transition:
Каждый из описанных выше профилей содержит в себе узлы профиля соответствующие его типу. Для интерполированного профиля узлы являются структурами AgProfileNode, для чёрного профиля ProfileNode, а для красного профиля ProjectNode. За сортировку узлов в профиле отвечает тот, кто заполняет профиль, это необходимо для корректной обработки вертикальных стенок и обратных уклонов земли.
Если в чёрный профиль требуется внести изменения, то необходимо сделать его статическим. Для этого нужно свойству IsDynamicEarth класса Transition установить значение false и получить существующий профиль через свойство StaticEg.
Изменение коллекций узлов профилей выполняется аналогично работе с массивами.
В этом примере мы выберем вершину красного профиля и сгладим её путём удаления существующей вершины и добавления двух новых с заранее рассчитанными уклонами на заданном расстоянии друг от друга.
Аналогично предыдущему примеру, определим активную модель подобъекта. Рамкой укажем область в которой располагается вершина красного профиля с помощью метода GetFrame() класса CadCursors. Полученные значения координат необходимо переконвертировать из координат экрана в координаты профиля. Конвертация осуществляется методом UnProjectBox() класса CadView. Далее определим какая вершина профиля попадает в границы указанных координат. Для этого следует воспользоваться методом Contains() структуры BoundingBox2D и передать в него положение узла красного профиля.
Определив необходимую вершину, рассчитаем положение новых вершин и внесём изменения в проектный профиль.
В теле программного модуля объявите команду, и декорируйте её атрибутом «cmd». Команда «smooth_peak» предложит пользователю выбрать рамкой вершину красного профиля и указать расстояние между новыми сглаживающими вершинами.
... [cmd("smooth_peak")] private void SmoothPeak() { //Получаем модель текущей трассы. Если текущей является не трасса, то активируется последняя активная трасса 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; //Выбираем рамкой вершину красного профиля, которую требуется сгладить RectangleD rectangle; FrameSelectType ft; if (CadCursors.GetFrame(cadview, out rectangle, out ft, "Выберите вершину:") != GetPointResult.Accept) return; var bounds = rectangle.ToBoundingBox(); bounds = cadview.UnProjectBox(bounds); //Получаем красный профиль и находим указанную вершину на этом профиле var profile = alignment.Transitions[0].RedProfile; for (int i = 1; i < profile.Count - 1; i++) { var curNode = profile[i]; //Если это выбранная вершина, то предлагаем пользователю ввести длину сглаживающего сегмента, //высчитываем положение новых вершин, добавляем их в профиль и удаляем исходную вершину if (bounds.Contains(curNode.Position) != ContainmentType.Disjoint) { var length = 0.0; var res = CadCursors.GetDouble(cadview, ref length, "Укажите длину сглаживающего сегмента:"); if (res != GetPointResult.Accept) return; var prevNode = profile[i - 1]; var nextNode = profile[i + 1]; var prevLength = curNode.Station - prevNode.Station; var curLength = nextNode.Station - curNode.Station; if (prevLength < length * 0.5 || curLength < length * 0.5) { MessageDlg.Show("Необходимо указать меньшее значение длины сегмента сглаживания.", MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1); return; } var prevIncline = (curNode.Elevation - prevNode.Elevation) / prevLength; var curIncline = (nextNode.Elevation - curNode.Elevation) / curLength; var startStation = prevNode.Station + (prevLength - length * 0.5); var startElevation = prevNode.Elevation + prevIncline * (prevLength - length * 0.5); var startNode = new ProjectNode(startStation, startElevation, 0, 0, ProjectNodeFlags.UseRadius); var endStation = curNode.Station + length * 0.5; var endElevation = curNode.Elevation + curIncline * length * 0.5; var endNode = new ProjectNode(endStation, endElevation, 0, 0, ProjectNodeFlags.UseRadius); profile.BeginUpdate(); try { profile.Add(startNode); profile.Add(endNode); profile.Remove(curNode); } finally { profile.EndUpdate(); } return; } } } } ...
Теперь необходимо сформировать наш файл .plugin. Заполните его следующим образом.
{ "assemblies": { "TutorialEditAlignment": { "assembly": "TutorialEditAlignment.dll, TutorialEditAlignment.ModulePluginHost" } }, "actions": { "id_add_vertex_to_alignment": { "cmd": "add_vertex_to_alignment", "title": "Добавить вершину в план линии" }, "id_smooth_peak": { "cmd": "smooth_peak", "title": "Сгладить вершину профиля" } }, "menubars": { "rbproj": { "items": [ { "id": "tutorial_menu", "title": "Tutorial", "items": [ "id_add_vertex_to_alignment", "id_smooth_peak" ] } ] } } }
Результатом запуска проекта будет появление в главном меню пункта «Tutorial», с подпунктами, которые будут работать в соответствии с описанными выше алгоритмами.