====== Выбор модели подобъекта и преобразование координат ======
В терминологии программного комплекса [[http://www.topomatic.ru|Топоматик Робур]] подобъектами принято называть модели [[road:road:start|автомобильных]] и [[rail:rail:start|железных дорог]], а также [[road:work_with_track:start|модели трасс]].
Подобъекты являются наследниками класса [[developers:references:topomatic.alg.model.alignmentmodel|AlignmentModel]]. Они содержат в себе информацию о плане линии, продольных и поперечных профилях и прочие данные присущие конкретному типу подобъекта.
При работе с подобъектами, подавляющее большинство операций производится посредством изменения состояния экземпляра класса [[developers:references:topomatic.alg.alignment|Alignment]], получаемого через свойство [[developers:references:topomatic.alg.model.alignmentmodel.alignment|Alignment]] модели подобъекта.
Доступ к наиболее часто используемые данным подобъекта осуществляется через следующие свойства [[developers:references:topomatic.alg.alignment|Alignment]]:
* [[developers:references:topomatic.alg.alignment.corridor|Corridor]] - поперечные профили
* [[developers:references:topomatic.alg.alignment.plan|Plan]] - план линии
* [[developers:references:topomatic.alg.alignment.stationing|Stationing]] - пикетаж
* [[developers:references:topomatic.alg.alignment.transitions|Transitions]] - продольные профили
===== Подготовка модуля =====
Создайте и настройте новый [[developers:tutorial:module|модуль]] для подключения к программному комплексу [[http://www.topomatic.ru|Топоматик Робур]].
С помощью диалогового окна Менеджер ссылок добавьте ссылки на следующие библиотеки:
* [[developers:references:topomatic.alg|Topomatic.Alg]] - базовые классы подобъектов
* [[developers:references:topomatic.cad.foundation|Topomatic.Cad.Foundation.dll]] - базовые математические типы и операции
* [[developers:references:topomatic.cad.view|Topomatic.Cad.View.dll]] - элемент управления для отображения слоёв моделей
Выбор подобъекта на экране осуществляется с помощью свойства [[developers:references:topomatic.cad.view.cadview.selectionset|SelectionSet]] класса [[developers:references:topomatic.cad.view.cadview|CadView]]. Подробнее о выборе объектов на экране можно узнать в разделе руководства [[developers:tutorial:cadcursors|Выбор элемента и ввод через курсор]]. Для выбора подобъекта воспользуемся методом [[developers:references:topomatic.cad.view.selectionset.selectobjectsatscreen_system.predicate_1_system.string_arr_system.string|SelectObjectsAtScreen]] с соответствующим [[https://docs.microsoft.com/ru-ru/dotnet/api/system.predicate-1?view=net-6.0|предикатом]]. Выбираемый объект должен реализовывать интерфейс IWrapped, а объект возвращаемый его свойством WrappedObject должен быть экземпляром класса [[developers:references:topomatic.alg.alignment|Alignment]].
===== Преобразование координат =====
В этом примере мы укажем точку на плане и определим соответствующие этой точке пикетаж, смещение от оси и расстояние от начала трассы.
Сперва необходимо получить геометрию плана линии. Для этого у [[developers:references:topomatic.alg.alignment|Alignment]]'а получим значение свойства [[developers:references:topomatic.alg.alignment.plan|Plan]]. Далее у полученного плана линии ([[developers:references:topomatic.alg.plan.planline|PlanLine]]) вернём значение свойства [[developers:references:topomatic.alg.plan.planline.compoundline|CompoundLine]]. Смещение и расстояние от начала трассы получается методом [[developers:references:topomatic.alg.compoundline.postostaoffset_topomatic.cad.foundation.vector2d_ref_system.double_ref_system.double|PosToStaOffset]] класса [[developers:references:topomatic.alg.compoundline|CompoundLine]], которому передаётся указанная на плане точка.
Для преобразования расстояния от начала трассы в пикетаж получим пикетаж подобъекта через свойство [[developers:references:topomatic.alg.alignment.stationing|Stationing]] у [[developers:references:topomatic.alg.alignment|Alignment]]'а. Преобразование осуществляется методом [[developers:references:topomatic.alg.stationing.algbasestationing.stationtostring_system.double|StationToString]] класса [[developers:references:topomatic.alg.stationing.algbasestationing|AlgBaseStationing]].
В теле программного модуля объявите команду, и декорируйте её атрибутом «cmd». Команда «define_stationing_at_point» предложит пользователю указать точку на плане и определит её пикетаж, расстояние от начала трассы и смещение от оси подобъекта.
...
[cmd("define_stationing_at_point")]
private void DefineStationingAtPoint()
{
var cadview = CadView;
if (cadview == null) return;
//Выбираем трассу
object select;
var res = cadview.SelectionSet.SelectOneObjectAtScreen(
o => o is IWrapped && ((IWrapped)o).WrappedObject is Alignment,
out select, "Выберите подобъект:");
cadview.SelectionSet.Clear();
if (res != GetPointResult.Accept) return;
var alignment = ((IWrapped)select).WrappedObject as Alignment;
var compound = alignment.Plan.CompoundLine;
var stationing = alignment.Stationing;
//Указываем точку, в которой требуется определить пикетаж
Vector3D point;
var getPointRes = CadCursors.GetPoint(cadview, out point, "Укажите точку определения пикетажа:");
if (!getPointRes) return;
//Определяем расстояние от начала пути и величину смещения до указанной точки
double station, offset;
var convertRes = compound.PosToStaOffset(point.Pos, out station, out offset);
if (!convertRes)
{
MessageDlg.Show("Не удалось определить расстояние от начала пути в указанной точке.",
MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
return;
}
//Определяем пикетаж на полученном расстоянии от начала пути и выводим данные на экран
var pkPlus = stationing.StationToString(station);
var msg = string.Join(Environment.NewLine,
$"ПК{pkPlus}",
$"Расстояние: {ValueConverter.FloatToStr(station, 3)}",
$"Смещение: {ValueConverter.FloatToStr(offset, 3)}");
MessageDlg.Show(msg, MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
}
...
{{ :developers:tutorial:alignmentedit:tutalgpnttopksta.png?nolink&600 |}}
Далее выполним обратную операцию преобразования. Определим точку на плане по пикетажу и смещению введёнными пользователем. Для этого потребуется преобразовать значение пикетажа в расстояние от начала трассы с помощью метода [[developers:references:topomatic.alg.stationing.algbasestationing.trystringtostation_system.string_ref_system.double|TryStringToStation]] класса [[developers:references:topomatic.alg.stationing.algbasestationing|AlgBaseStationing]]. Точка на плане определяется методом [[developers:references:topomatic.alg.compoundline.staoffsettopos_system.double_system.double_ref_topomatic.cad.foundation.vector2d|StaOffsetToPos]] класса [[developers:references:topomatic.alg.compoundline|CompoundLine]], в который передаётся расстояние от начала трассы и смещение.
В теле программного модуля объявите команду, и декорируйте её атрибутом «cmd». Команда «define_point_at_stationing» предложит пользователю ввести пикетаж и смещение от оси подобъекта и определит координаты точки, а также расстояние от начала трассы для введённых параметров.
...
[cmd("define_point_at_stationing")]
private void DefinePointAtStationing()
{
var cadview = CadView;
if (cadview == null) return;
//Выбираем трассу
object select;
var res = cadview.SelectionSet.SelectOneObjectAtScreen(
o => o is IWrapped && ((IWrapped)o).WrappedObject is Alignment,
out select, "Выберите подобъект:");
cadview.SelectionSet.Clear();
if (res != GetPointResult.Accept) return;
var alignment = ((IWrapped)select).WrappedObject as Alignment;
var compound = alignment.Plan.CompoundLine;
var stationing = alignment.Stationing;
//Вводим пикетаж и определяем расстояние от начала пути
var pkPlus = "0+00.00";
res = CadCursors.GetString(cadview, ref pkPlus, "Введите пикетаж в формате ПК+:");
if (res == GetPointResult.Cancel) return;
double station;
if (!stationing.TryStringToStation(pkPlus, out station))
{
MessageDlg.Show("Указанный пикетаж не найден.", MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
return;
}
//Вводим смещение
var offset = 0.0;
res = CadCursors.GetDouble(cadview, ref offset, "Введите смещение:");
if (res == GetPointResult.Cancel) return;
//Определяем координаты по задданым значениям и выводим значения на экран
Vector2D point;
var vectorFound = compound.StaOffsetToPos(station, offset, out point);
if (!vectorFound)
{
MessageDlg.Show("Не удалось определить координаты.", MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
return;
}
var msg = string.Join(Environment.NewLine,
$"X: {ValueConverter.FloatToStr(point.X, 3)}",
$"Y: {ValueConverter.FloatToStr(point.Y, 3)}",
$"Расстояние: {ValueConverter.FloatToStr(station, 3)}");
MessageDlg.Show(msg, MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
}
...
{{ :developers:tutorial:alignmentedit:tutalgpkoffsettopos.png?nolink&600 |}}
Теперь необходимо сформировать наш файл .plugin. Заполните его следующим образом.
{
"assemblies": {
"TutorialEditAlignment": {
"assembly": "TutorialEditAlignment.dll, TutorialEditAlignment.ModulePluginHost"
}
},
"actions": {
"id_define_stationing_at_point": {
"cmd": "define_stationing_at_point",
"title": "Определить пикетаж в точке"
},
"id_define_point_at_stationing": {
"cmd": "define_point_at_stationing",
"title": "Определить координаты по пикетажу и смещению"
}
},
"menubars": {
"rbproj": {
"items": [
{
"id": "tutorial_menu",
"title": "Tutorial",
"items": [
"id_define_stationing_at_point",
"id_define_point_at_stationing"
]
}
]
}
}
}
Результатом запуска проекта будет появление в главном меню пункта «Tutorial», с подпунктами, которые будут работать в соответствии с описанными выше алгоритмами.
[[developers:tutorial:tutorialcode|Исходный код]] примера расположен в проекте **"TutorialEditAlignment"**.