Создание ГИС на Visual FoxPro средствами MapInfo Professional

Новости

Цель статьи: продемонстрировать основные приёмы работы при создании геоинформационной системы на VFP, с применением MapInfo Professional. Материал ориентирован на IT-специалистов, работающих в земельных комитетах, геодезических или землеустроительных организациях.
Введение
Запуск экземпляра MapInfo
Создание карт
Окно карты MapInfo в вашем приложении
«Знать ГДЕ – это только начало!»

1.Введение

Земля и объекты недвижимости – надёжный и, к тому же, стабильно растущий актив в большинстве государств. Как и всякий ресурс, земельные участки и другие объекты недвижимости необходимо учитывать. Инвентаризация земельных участков, расположенных на них объектов недвижимости, оценка, а в последующем, переоценка земли и строений осложняется интенсивно меняющимися окружающими условиями, общегосударственным и муниципальным законотворчеством. Расчётные операции, проводимые при оценке земли и объектов недвижимости, используют большое количество параметров имеющих географическую смысловую составляющую. Что, вызывает потребность в информационных системах, позволяющих аналитически обрабатывать географическую информацию.

Продукт MapInfo Professional американской компании MapInfo Corporation, предоставляет возможность включать в ваше приложение на VFP векторные карты совместно с инструментами анализа географической информации. MapInfo Professional позволяет выполнять программы MapBaisic – языке программирования, входящем в интегрированную среду разработки MapInfo. Разработчику предоставляется COM интерфейс MapInfo, позволяющий управлять отображением карт, а так же выполнять отдельные команды и программы MapBaisic.

2. Запуск экземпляра MapInfo

После установки MapInfo Professional в реестре OC Windows регистрируется класс «MapInfo.Application», если вы используете MapInfo Runtime, то класс «MapInfo.Runtime». Таким образом, запуск MapInfo:
Public poMI As Object
m.poMI=CreateObject([MapInfo.Application])

Так, как метода [.Quit] COM модель MapInfo не предусматривает, завершение работы экземпляра MapInfo реализуется следующим образом:
m.poMI=Null
Release poMI

3.Создание карт

Для включения векторной карты в ваше приложение, вы должны располагать такой картой. В некоторые дистрибутивы MapInfo Professional включены карты большинства стран и крупных городов Европы, Азии и Северной Америки. Но что делать, если вам нужна межевая карта садово-дачных участков в пригороде какого-нибудь Смоленска или Стамбула. Не знаю как в Турции, но качество материалов, которые вам по умеренной цене может предоставить земельный комитет администрации какого-нибудь Смоленска, вас не устроит. (Может быть, вы даже работаете в этом земельном комитете?) А карта нужна! Но, вы узнаёте, что некая землеустроительная контора проводила геодезическую съёмку и межевание той самой местности, карта которой вам так нужна! (А может, вы работаете в этой землеустроительной конторе?)

Итак, рассмотрим создание карты по координатным данным, полученным геодезической съёмкой. Не вдаваясь в подробности, можно считать что, карта в MapInfo это таблица, каждой строке которой может соответствовать графический объект. С помощью метода [.Do()] COM объекта MapInfo, выполним следующую последовательность команд MapBasic:
Local lcCommandMapBaisic As Character
Text To m.lcCommandMapBaisic TextMerge Noshow

Create Table «myMap» (c1 Integer,c2 Char(100))
File «c:\gis\myMap.TAB»
Type NATIVE
Charset «WindowsCyrillic»

Create Map For «myMap»
CoordSys NonEarth Units «m» Bounds (0,0) (10000,10000)

Browse * From «myMap»
Map From «myMap»

EndText

m.poMI.Do(m.lcCommandMapBaisic)
Release lcCommandMapBaisic

Здесь, первая команда [Create Table …] создаёт таблицу [myMap] с столбцами [c1] типа Integer и [c2] типа Char(100), файл таблицы размещается в каталоге [c:\gis\], тип таблицы – внутренний формат MapInfo, кодовая страница таблицы [WindowsCyrillic]. Следующая команда [Create Map …], создаёт в таблице [myMap] столбец [obj], имеющий специальный тип MapInfo, позволяющий создавать и хранить графические объекты, составляющие карту. Система координат карты задаётся фразой [CoordSys NonEarth], что соответствует декартовой системе координат и подходит для картографирования плана местности. Параметр [Units] задаёт единицу измерения 1 метр, а параметр [Bounds] границы карты. Оставшиеся две команды MapBasic [Browse …] и [Map From …] открывают окна таблицы и карты соответственно и имеют интуитивно понятный синтаксис.

Поле карты создано. Следующий шаг – добавление графических примитивов на карту. Пример:
Local lcCommandMapBaisic As Character
Text To m.lcCommandMapBaisic TextMerge Noshow

Set CoordSys NonEarth Units «m» Bounds (0,0)(10000,10000)

Dim loRegion As Object
Create Region Into Variable loRegion 3
6 (10,100)(100,100)(100,90)(20,90)(20,70)(10,70)
6 (110,100)(120,100)(120,50)(80,50)(80,60)(110,60)
4 (10,50)(70,50)(70,60)(10,60)

Insert Into «myMap» (c1,obj) Values (1,loRegion)
UnDim loRegion

Set Map Zoom Entire

EndText

m.poMI.Do(m.lcCommandMapBaisic)
Release lcCommandMapBaisic

Обратите внимание – первой командой MapBasic [Set CoordSys …] мы устанавливаем соответствие координат создаваемых графических объектов координатному полю карты. Затем, объявляем переменную [loRegion] типа [Object]. Командой [Create Region …] создаём графический объект, сохраняя результат в ранее объявленную переменную. После чего, командой [Insert Into …] вставляем в таблицу [myMap] новую строку, используя 1, как значение для поля [c1] и переменную [loRegion], как значение для поля [obj]. Команда [UnDim …] удаляет переменную [loRegion]. Последняя команда MapBasic [Set Map Zoom Entire] – масштабирует изображение в рабочей области окна карты.

Вот вид окна MapInfo Professional, демонстрирующий результат нашей работы:

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

Одно важное замечание. Вы, конечно, обратили внимание, на то обстоятельство, что создавая карту, мы не использовали масштаб. Ничего странного – в векторном картографировании очень удобно создавать карты именно в масштабе 1:1, как мы и сделали, для просмотра карты на экране можно выбрать произвольный масштаб. При печати твёрдых копий карт или планов, принято придерживаться стандартных масштабов 1:200, 1:500, 1:1000, 1:2000 и т.д.

4.Окно карты MapInfo в вашем приложении

Код класса VFP, демонстрирующий приёмы работы с картой MapInfo:
* пример использования
*Public poFM As Form
*m.poFM=Createobject([form4map],[c:\gis\myMap.tab])
*m.poFM.Show()
*————————————————————————
Define Class form4map As Form
map_hwnd=0 && указатель окна карты

Procedure Init
Lparameters lcFileMap
This.AddProperty([Map],Createobject([Mapinfo.Application]))
* окно следующего документа MapInfo
* будет дочерним окном этой формы
This.Map.Do([Set Next Document Parent ]+;
Transform(This.HWnd)+[ Style 1])
* открытие карты
This.Map.Do([Open Table «]+m.lcFileMap+[» ]+;
[Map From «]+Juststem(m.lcFileMap)+[«])
* определение указателя окна карты
This.map_hwnd=Val(This.Map.Eval([WindowInfo(FrontWindow(),12)]))
* объявление функции для управления размером окна карты
Declare Integer MoveWindow In user32 ;
Integer HWnd,;
Integer x,;
Integer y,;
Integer nWidth,;
Integer nHeight,;
Integer bRepaint
Endproc

Procedure Resize
* изменение размеров окна карты до размеров, включающей её формы
MoveWindow(This.map_hwnd,0,0,This.Width,This.Height,0)
Endproc

Procedure Destroy
* завершение работы COM объекта MapInfo
This.Map=Null
Clear Dlls MoveWindow
Endproc

Enddefine

В результате, форма VFP содержит план (карту), см. рис.

Благодаря применению api-функции [MoveWindow] в методе [Resize] формы, при изменении размеров формы карта, находящаяся в окне MapInfo, автоматически масштабируется к размерам родительской формы.

5.«Знать ГДЕ – это только начало!»

Пусть, мы располагаем планом (картой) некоторого населённого пункта, см. рис.:

Предположим, что требуется смоделировать чрезвычайную ситуацию: в результате прорыва плотины на реке Хауки, произойдёт затопление территории до 700 метров от береговой линии. Требуется определить, сколько всего, и какие именно городские строения могут попасть в зону затопления.

Построим 700 метровую буферную зону от правого берега реки Хауки:
Local lcCommandMapBaisic As Character
Text To m.lcCommandMapBaisic TextMerge Noshow

Dim loFlooding_zone as Object

Create Object As Buffer From Selection
Into Variable loFlooding_zone
Width 700 Units «m»

Select c1,c2 From «myMap»
Where myMap.obj WithIn loFlooding_zone
Group By c1,c2
Order by c1

UnDim loFlooding_zone

EndText

* SelectionInfo() – функция MapBasic,
* в зависимости от передаваемого параметра возвращает информацию
* о выделенной области на текущей карте, в данном случае
* количество выделенных объектов
If Val(m.poMI.Eval([SelectionInfo(3)]))>0
m.poMI.Do(m.lcCommandMapBaisic)
Else
Messagebox([Для построения буферной зоны ;
необходимо выбрать объект на карте.],48,[Внимание],10000)
Endif
Release lcCommandMapBaisic

Рассмотрим приведённый код. Команда [Create Object As Buffer …] – создаёт требуемую буферную зону, сохраняя результат в переменной [loFlooding_zone]. Следующая команда – SQL-запрос, где фразу [Where …] следует понимать так: объекты карты [myMap] внутри (WithIn) буферной зоны [loFlooding_zone]. Если на момент выполнения этого скрипта на карте нет выделенных объектов, MapInfo сгенерирует ошибку, по этому, перед отправкой на выполнение, с помощью метода [.Eval(…)] COM модели MapInfo, мы выполняем функцию SelectionInfo() для проверки наличия на карте выделенных объектов.

В результате MapInfo формирует специальный объект [Selection], в котором содержатся все графические объекты карты, попадающие в 700 метровую буферную зону от береговой линии реки Хауки. На рисунке эти объекты помечены красными насечками.

MapInfo поддерживает следующие пространственные операторы над географическими объектами:
Contains
«Содержит»
Объект A содержит объект Б, если центроид Б лежит в границах A.

Contains Entire
«Полностью содержит».
Объект A полностью содержит объект Б, если граница Б полностью лежит внутри границ A.

WithIn
«Внутри».
Объект A лежит внутри объекта Б, если его центроид лежит в границах Б.

Entirely WithIn
«Полностью внутри».
Объект A лежит полностью внутри объекта Б, если его граница полностью лежит внутри границ Б.

Intersects
«Пересекает».
Объект A пересекается с объектом Б, если они имеют хотя бы одну общую точку.

Различие между [Contains] и [WithIn], с одной стороны, и [Contains Entire] и [Entirely WithIn], с другой, состоит в том, что [Contains] и [WithIn] основаны на анализе центроида объекта, а [Contains Entirely] и [Entirely WithIn] — на анализе всего объекта.

Географические функции:
Area(…)
Возвращает площадь объекта

Distance(…)
Возвращает расстояние между двумя точками

ObjectLen(…)
Возвращает длину объекта

Perimeter(…)
Возвращает периметр объекта

Применение в пространственных SQL-запросах MapInfo таких инструментов позволяет проводить географический анализ карты. Девиз разработчиков MapInfo: «Знать ГДЕ – это только начало!»

В завершение, код позволяющий получить данные о выделенных объектах, составляющих буферную зону.
Create Cursor Flooding_obj (id_obj Integer, name_obj Character(70))

Local lnNRows As Integer
m.lnNRows=Val(m.poMI.Eval([SelectionInfo(3)]))

If m.lnNRows>0
For m.i=1 To m.lnNRows
m.poMI.Do([Fetch Rec ]+Transform(m.i)+[ From «Selection»])
Insert Into Flooding_obj (id_obj, name_obj) ;
Values (Val(m.poMI.Eval([Selection.c1])),;
m.poMI.Eval([Selection.c2]))

Endfor
Endif

В данном примере организован перебор всех строк специальной таблицы MapInfo: [Selection], в которую MapInfo помещает все выделенные объекты карты.

На этом всё. Спасибо за внимание.
Замечания принимаются.