Как создать свою ГИС с помощью GIS ToolKit Active

Урок 7. Редактирование групп выделенных объектов

Автор: Дарья Лунченко

Ранее мы уже научились выполнять некоторые операции редактирования объектов векторных карт. Теперь мы рассмотрим, как применить функции редактирования к группе выбранных объектов, а также разберемся с функциями нарезки и сшивки объектов.

После прохождения этого урока наше приложение позволит нам:

  • перемещать выделенные объекты;
  • удалять выделенные объекты;
  • сшивать два объекта, учитывая их семантические характеристики;
  • разрезать площадной объект по линии.

Внешний вид приложения представлен на рис. 1.

Рисунок 1 – Внешний вид приложения
 

Скачать рабочий образец программы, и ее исходный код можно на страничке "Дополнительные материалы к уроку 7". Если у вас не установлен GIS ToolKit Active, то для запуска приложения вам потребуется загрузить библиотеки GIS ToolKit, и выполнить их регистрацию. Все необходимые библиотеки и короткая инструкция размещены на этой же странице.

1. Перемещение группы объектов

В уроке №3 мы разобрались, как организовать выделение объектов на карте. Теперь рассмотрим, как переместить группу выделенных объектов на указанное пользователем расстояние (рис.2). Режим перемещения группы объектов будет запускаться той же кнопкой, которой ранее выполнялось перемещение одного объекта. Однако мы внесем в нашу программу небольшие изменения, чтобы она вела себя следующим образом:

  • если на карте есть выделенные объекты, то при нажатии на кнопку "Перемещение", программа задает пользователю уточняющий вопрос: "Вы действительно хотите переместить выделенные объекты?"
  • при положительном ответе программа работает с выделенными объектами;
  • если на карте нет выделенных объектов или дан отрицательный ответ на вопрос программы, то осуществляется обработка одного объекта, который пользователь выберет на карте.

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

Рисунок 2 – Перемещение группы объектов

Переходим к реализации данной функции:

  • создадим новый класс FMoveObjects.cs, в который поместим все функции, связанные с перемещением нескольких объектов;
  • при нажатии на кнопку перемещения объекта, вызываем функцию CheckMoveObj, в которой определяем перемещается группа объектов или один, а также подсчитываем сумму выделенных объектов, далее с помощью сообщения MessageBox спрашиваем у пользователя подтверждение перемещения группы объектов;

  • в событии по нажатию мыши на карте - MapView1_OnMapMouseDown, определяем функцию MoveObjects_MouseDown, в которой, используя компонент доступа к координатам карты MouseXY и структуру TxDoublePoint Point0, запоминаем координаты точки первого нажатия мыши на передвигаемом объекте;

  • в событии по отжатию мыши на карте - MapView1_OnMapMouseUp, определяем функцию MoveObjects_MouseUp, а в классе FMapAPI.cs импортируем функцию для создания копии объекта векторной карты mapCreateCopyObject;

  • в функции MoveObjects_MouseUp, проходим в цикле по всем выделенным объектам, и создаем их копии, помещая их в отдельный список ObjCopyHandle, также рассчитываем смещение между точками нажатия мыши на карте;

  • создаем новый объект электронной карты axMapObj - MapObjForMove, и записываем в него ранее созданные копии объектов, далее перемещаем их с помощью функции MAPAPI mapRelocateObject, и сохраняем в список ObjNumberForDelete для последующего их удаления;

  • в событии по двойному нажатию мыши на карте - MapView1_OnDblClick, определяем функцию MoveObjects_MouseDblClick(), в которой, используя функцию MAPAPI mapDeleteObjectByNumber, удаляем копии объектов, и проходя в цикле по исходным выделенным объектам, перемещаем их, сохраняя изменения на карте;

2. Удаление группы объектов

Рассмотрим, как удалить группу выделенных объектов (рис.3). Для удаления группы используется та же кнопка, что и для удаления одного объекта. Однако в обработчике нажатия этой кнопки добавлена операция проверки наличия на карте выделенных объектов. И если такие есть, то программа уточняет у пользователя: "Вы действительно хотите удалить выбранные объекты?". При положительном ответе программа работает с группой выделенных объектов.

Рисунок 3 – Удаление группы выделенных объектов

Реализация операции удаления группы выделенных объектов:

  • для удаления объектов, выделенных с помощью клика мыши, добавим в функцию SelectByClickFunc список ObjHandle, в который, используя функцию MAPAPI mapGetObjectNumber, сохраним номера по порядку выделяемых объектов;
  • при нажатии на кнопку удаление объектов, определяем функцию DeleteObjFunc, в которой, подсчитываем количество выделенных объектов, и, спрашивая пользователя подтверждение, удаляем их, если они были выделены по клику - функцией MAPAPI mapDeleteObjectByNumber, если другим способом - функцией axMapObj.Delete;

  • для удаления объектов выделенных другим способом, подсчитываем количество выделенных объектов и затем, запросив пользователя подтверждение, удаляем их функцией axMapObj.Delete; 

3. Сшивка объектов

Функция сшивки объектов применяется для того, чтобы объединить между собой два однотипных линейных или площадных объекта. При сшивке объектов, необходимо учесть их семантические характеристики, а также минимальное расстояние в метрах (допуск согласования), при котором возможна сшивка (рис. 4). В нашей реализации мы будем проверять значения семантик двух указанных пользователем для сшивки объектов и, если у объектов есть семантики с одинаковым кодом, но разными значениями, то операции сшивки будет прерываться. Если у одного объекта есть семантики, которых нет у другого, то в объект, созданный слиянием, будет добавлен объединенный список семантик. Допуск согласования в нашем приложении будет устанавливаться пользователем перед выполнением операции сшивки, для чего добавим форму запроса этого параметра. Если допуск не был установлен ранее, программа выдаст запрос на его установку при выполнении сшивки.

Рисунок 4 – Сшивка объектов

Переходим к поэтапной реализации данной функции:

  • добавим на панель инструментов для редактирования кнопку «Параметры редактора» ;
  • создадим новую форму Windows Form, и добавим на неё стандартные элементы: textBox – для ввода значения допуска в метрах, и две кнопки Button : «Установить» или «Отменить» значение допуска (рис. 5);

Рисунок 5 – Форма «Параметры редактора»

  • при нажатии на кнопку параметры редактора, определяем функцию EditSettingsFunc, в которой, вызываем созданную нами форму, и устанавливаем значение допуска согласования, для того, чтобы не вводить при каждом запуске программы допуск заново, установим его, как сохраняемый параметр (см. п.3, урок №6);

  • добавляем на панель инструментов кнопку «Нарезка и сшивка объектов» , при нажатии на которую, добавляем панель инструментов ToolStrip, где размещаем две кнопки «Сшивка объекта» , «Рассечение объекта линией» ;
  • при нажатии на кнопку нарезки и сшивки объектов, определяем функцию CrossObjFunc, в которой вызываем форму для ввода допуска согласования, если значение не было введено ранее, а также устанавливаем панель инструментов «Нарезка и сшивка объектов» внизу поля карты;

  • добавляем класс FCrossCutObj.cs, который будет содержать функции по нарезке и сшивке объектов, далее добавляем на форму компонент построения пересечения двух объектов карты axMapCross;
  • с помощью свойства MapCross1.precision устанавливаем введенный нами ранее допуск согласования, и по клику мыши выбираем два объекта для сшивки;

  • используем свойства MapObj1.Local и MapCross1.LocalOut для определения типа результирующего объекта;

  • для анализа семантических характеристик объектов создаем списки, в которые добавляем, соответственно, наименования семантик 1-го и 2-го объектов и их значения, используя функции axMapObj.Semantic.SemanticName_get и axMapObj.Semantic.SemanticValue_get;

  • определяем в каком из объектов семантических характеристик больше, и устанавливаем соответствующие флаги: obj1 – если у 1-го, и obj2 – у 2-го;

  • проходим в цикле по всем семантическим характеристикам двух объектов, и сравниваем их между собой, если наименование семантик и их значения совпадают у двух объектов, уменьшаем счётчик obj12count – содержащий количество семантик;
  • при несовпадении значений одной и той же семантики у двух объектов, выдаем предупреждающее сообщение и прерываем операцию сшивки;

  • при несовпадении наименования семантик, добавляем соответствующие код семантической характеристики и её значение в списки AddSemanticCode и AddSemanticValue;

  • используем функцию MapCross.ExecuteUnion, для построения объединения исходных объектов, если объединение произошло, но количество семантических характеристик не совпадает, то просматриваем списки AddSemanticCode, AddSemanticValue и если они не пусты, добавляем к результирующему объекту недостающие семантики;

4. Рассечение площадного объекта линией

Для рассечения площадного объекта необходимо выбрать объект на карте, после чего провести произвольную линию, по которой будет рассекаться объект (рис.6). По окончанию операции, создаётся два новых объекта по линии рассечения.

Рисунок 6 – Рассечение площадного объекта

Реализация операции рассечения площадного объекта:

  • при нажатии на кнопку «Рассечение объекта линией», переходим в событие ButtonAction, в котором, устанавливаем флаг нарезки объекта cutobjcount = 1;
  • в классе FCrossCutObj.cs, определяем функцию CutObjectFunc, в которой при флаге cutobjcount = 1, выполняем выбор объекта на карте, при отжатии кнопки мыши устанавливаем флаг cutobjcount = 2;

  • при флаге cutobjcount = 2, определяем структуру для описания объекта, рассекающего выбранный axGisToolKit.TxMapObjectInfo, в которой устанавливаем его внешний код и тип, далее включаем режим создания линейного объекта;

  • в событии, происходящем при окончании редактирования по двойному щелчку мыши MapEditMetric1_OnStopAction, устанавливаем флаг cutobjcount = 3, в классе FMapAPI.cs, импортируем функции mapCreateObjectCutByLine – для рассечения замкнутого объекта по линии и mapGetNextCut – для получения объектов при рассечении;

  • при cutobjcount = 3, используем импортируемые функции для создания класса рассечения и нахождения результирующих объектов после рассечения, далее, используя свойство axMapObj.CommitAsNew, записываем их как новые объекты, и удаляем исходный рассекающий и рассекаемый объект.

В этом уроке на двух примерах мы увидели, как создать режимы редактирования групп выделенных объектов, а также освоили более сложные операции сшивки и нарезки объектов, требующие учитывать семантики объектов или дополнительные данные. Надеемся, что приведенные примеры, помогут вам понять, как используя функционал GisToolKit Active, создавать разные режимы редактирования векторных данных. А в следующем уроке мы будем разбираться с функциями для работы с растровыми изображениями.

Смотреть: Дополнительные материалы к уроку 7