Всем привет! Хочу с Вами поделиться своим опытом работы с таким SDK как MapXtreme .Net от фирмы Pitney Bowes. Как сказано у них на сайте:
MapInfo MapXtreme for .Net — это комплект разработчика программного обеспечения ГИС в среде Microsoft .Net, позволяющий встраивать картографические и ГИС функции в бизнес-приложения.
Установка
Первым шагом была настройка машины к работе. Устанавливаем MS VisualStudio 2015 с сайта разработчика (на MSVS2010 работает, ниже версии не пробовал).
Скачиваем пакет установки с сайта разработчика. На портале для скачивания доступна триальная версия 7.1 на 60 дней (версия 8 доступна для покупки, разница между ними ощутимая, но затрагивает архитектуру MapXtreme. Основные операции остались неизменными).
Так же необходимо скачать карту мира, иначе зачем нам вообще нужна ГИС, не так ли? Для MapXtreme подходит карта ADC WorldMap Version 7.1.
Ставить именно в таком порядке, так как MapXtreme требует .Net.
Документация
Библиотека очень большая с большим количеством функций, но чтобы добраться до них нужна документация, а с ней у MapXtreme проблемы. После установки в каталоге с SDK можно найти
MapXtreme Developers Reference
MapXtreme Version 8.0 Developer Guide
Сами материалы содержат примеры на уровне капитана очевидность, либо отсутствуют вовсе. В интернете данная библиотека так же не содержит множества поясняющих ресурсов. Самый лучший был на сайте самого разработчика. Однако где-то полгода назад они закрыли к ней доступ и стали всех отправлять в тех.поддержку.
Кстати, пару слов о ней родимой:
Было 3-4 обращения к ним за помощью, и все разы мне говорили:
«Мы передали ваш запрос нашим разработчикам»
«Пришлите ваш исходный код нам, мы не понимаем вашу проблему» и т.д.
Для карты так же идет руководство, которое полезно. В нем описаны все теги и тпиа значений которые можно устанавливать.
Разработка
Если вы установили все верно, то VisualStudio при создание нового проекта у вас будет доступен тип проекта MapXtreme (у меня версия 8.0, т.к. мы купили лицензию).
Выбираем Windows Form App. Если в ToolBox не появились новые элементы открываем пункт меню
Tools → Choose ToolBox Items...
И в появившемся окне выбираем нужные нам инструменты:
Итак, мы все установили, настроили и готовы писать код MapXtreme предоставляет уже готовые компоненты для создания приложения. Вы можете сразу сделать панель инструментов MapXteme добавив на главную форму компонент ToolStrip, в котором хранятся необходимые нам кнопки.
Чтобы использовать выбранные нами кнопки свойству MapControl пропишем имя нашего элемента типа MapControl. У меня называется mapControl1, у вас оно может отличаться. Либо в конструкторе формы написать
private void Form1_Load(object sender, EventArgs e)
{
addrectangleToolStripButton1.MapControl = mapControl1;
....
}
Если все сделано правильно, то у вас должно получится вот так:
«Я сделал все правильно, выбрал инструмент для рисования, но у меня ничего не выходит! Почему?»
Чтобы решить данную проблему необходимо выбрать слой на котором мы будем рисовать и сделать его изменяемым. По умолчанию все слои на mapControl неизменяемые.
Мы можем решить нашу проблему средствами MapXtreme нажав кнопку «Layer Control» и поставив галочки в нужных местах.
Или сделать это прямо в коде:
var layerTemp = mapControl1.Map.Layers["wldcty25"];
LayerHelper.SetInsertable(layerTemp, true);//дает возможность рисовать на слое инструментами
LayerHelper.SetEditable(layerTemp, true); //делает наш слой изменяемым
Отмечу, что рисовать можно только на «верхнем» слое, то есть чтобы сейчас нарисовать объект мы должны наш слой «wldcty25» переместить вверх:
Или написать в коде:
mapControl1.Map.Layers.Move(lastPosition, nextPosition);
В результате нарисован наш первый объект:
Как я говорил ранее любая настройка может быть задана через интерфейс. Однако, заказчик чаще всего привередливый и ему нужны более гибкие/доступные элементы настройки поэтому далее я не буду рассказывать о том как настроить что либо через компоненты MapXtreme. Я покажу как это сделать через код.
Начать хочу со стиля. Основным классом отвечающим за оформление выступает CompositeStyle. В MapXtreme мы можем задавать стиль на слой и на объект. Отмечу, что стиль слоя перекрывает стиль объекта.
SimpleLineStyle border;//стиль линейного объекта
border= new SimpleLineStyle(<ширина линии в единицах MapXtreme>, <код стиля линии>, <цвет линии>)
SimpleInterior interior;//стиль внутренней области объекта
interior = new SimpleInterior(<код стиля>, <цвет переднего плана>,<цвет фона>)
AreaStyle polygon;//стиль который используя предыдущие два задает стиль для площадного объекта
polygon = new AreaStyle(border, interior);
SimpleLineStyle line;//стиль линейного объекта
line = new SimpleLineStyle(<ширина линии в единицах MapXtreme>, <код стиля линии>, <цвет линии>)
BasePointStyle point;//стиль точечного объекта
point = new SimpleVectorPointStyle(<код стиля>, <цвет точки>, <размер точки>)
CompositeStyle compStyle;//стиль применяемый к слою
compStyle = CompositeStyle(polygon, line, null, point);
Применим полученный стиль к слою:
FeatureOverrideStyleModifier fosm;
fosm = new FeatureOverrideStyleModifier(parStyleName, parStyleAlias, compStyle);
myLayer.Modifiers.Append(featureOverrideStyleModifier);
Применим полученный стиль к объекту:
Feature feature = null;
feature = new Feature(<класс описывающий наш объект>, compStyle);
Создание объекта
Для создания мультилинии или мультиполигона сначала создадим исходные данные:
//задаем первую часть мультиобъекта
DPoint[] pts1 = new DPoint[5];
pts1[0] = new DPoint(-20, 10);//произвольные координаты точек взятые для примера
pts1[1] = new DPoint(10, 15);
pts1[2] = new DPoint(15, -10);
pts1[3] = new DPoint(-10, -10);
pts1[4] = new DPoint(-20, 10);
//задаем вторую часть мультиобъекта
DPoint[] pts2 = new DPoint[5];
pts2[0] = new DPoint(-40, 50);
pts2[1] = new DPoint(60, 45);
pts2[2] = new DPoint(65, -40);
pts2[3] = new DPoint(25, 20);
pts2[4] = new DPoint(-40, 50);
//LineString создаем из массива элементов DPoint
LineString lineString1 = new LineString(coordSys, pts1);
LineString lineString2 = new LineString(coordSys, pts2);
Используя код выше создадим:
— мультиполигон
//Ring в заданной системе координат coordSys создается через LineString
Ring ring1 = new Ring(coordSys, lineString1);
Ring ring2 = new Ring(coordSys, lineString2);
Ring[] rng1 = new Ring[2];
rng1[0] = ring2;
rng1[1] = ring1;
//MultiPolygon состоит из массива Ring
MultiPolygon multiPol = new MultiPolygon(coordSys, rng1);
— мультилинию
//Curve в заданной системе координат coordSys создается через LineString
Curve curve4 = new Curve(coordSys, lineString1);
Curve curve5 = new Curve(coordSys, lineString2);
Curve[] crv = new Curve[2];
crv[0] = curve5;
crv[1] = curve4;
//MultiCurve состоит из массива Curve
MultiCurve mc = new MultiCurve(coordSys, crv);
Работа с картографической проекцией
Получение:
CoordSys сoordSys= mapControl1.Map.GetDisplayCoordSys();
Создание и изменение текущей системы координат:
CoordSys cs = Session.Current.CoordSysFactory.CreateCoordSys("EPSG:3395", CodeSpace.Epsg);
mapControl1.Map.SetDisplayCoordSys(cs);
На самом деле там очень много перегруженных конструкторов, но обычно двух хватает так как в практических задачах необходима работа в трех-четырех системах координат.
Я еще ничего не сказал про работу с растровыми изображениями. Она здесь так же есть. Однако если вы изменили систему координат, то ваше изображение вряд ли преобразуется если не прописать след. строчку:
mapControl1.Map.RasterReprojectionMethod = ReprojectionMethod.Always;
/**
*ReprojectionMethod имеет три состояния
* None = 0, //запрет на изменение растра
* Always = 1,//изменять всегда
* Optimized = 2//так и не понял зачем нужен, в моей практике он ничем не отличался от
* предыдущего
*/
Лично я работал только с GeoTiff. MapXtreme не работает напрямую с изображениями. Для того чтобы все было хорошо системе необходим *.tab файл, который будет содержать описание растра, систему координат, координаты углов.
Как делать *.tab для растра средствами MapXtreme я так и не нашел, интернет так же подсказки не дал и мне пришлось самому писать метод, который создавал бы этот файл:
private string CreateTabFile(List<DoublePoint> parImageCoordinate)//список координат углов
{
NumberFormatInfo nfi = new CultureInfo("en-US", false).NumberFormat;
var ext = m_fileName.Split(new Char[] { '.' });
var fileExt = ext[ext.GetLength(0) - 1];
string fileTabName = m_fileName.Substring(0, m_fileName.Length - fileExt.Length) + "TAB";
StreamWriter sw = new StreamWriter(fileTabName);
string header = "!tablen!version 300n!charset WindowsCyrillicn n";
sw.WriteLine(header);
string definitionTables = "Definition Tablen ";
definitionTables += "File "" + m_fileName + ""n ";
definitionTables += "Type "RASTER"n ";
for (var i = 0; i < parImageCoordinate.Count; i++)
{
definitionTables += "(" + parImageCoordinate[i].Longitude.ToString("N", nfi) + "," + parImageCoordinate[i].Latitude.ToString("N", nfi) + ") ";
definitionTables += "(" + parImageCoordinate[i].PixelColumn.ToString() + "," + parImageCoordinate[i].PixelRow.ToString() + ") ";
definitionTables += "Label "Точка " + (i + 1).ToString() + " ",n ";
}
definitionTables = definitionTables.Substring(0, definitionTables.Length - 4);
definitionTables += "n ";
definitionTables += "CoordSys Earth Projection 1, 104n ";
definitionTables += "Units "degree"n";
sw.WriteLine(definitionTables);
string metaData = "begin_metadatan";
metaData += ""\IsReadOnly" = "FALSE"n";
metaData += ""\MapInfo" = ""n";
string hash;
using (MD5 md5Hash = MD5.Create())
{
hash = GetMd5Hash(md5Hash, m_fileName);
}
metaData += ""\MapInfo\TableID" = "" + hash + ""n";
metaData += "end_metadatan";
sw.WriteLine(metaData);
sw.Close();
return fileTabName;
}
Метод GetMd5Hash взят с MSDN. Итак, теперь наш mapControl1 готов к работе с растром.
Пока все. Вышло и объемно, наверное. Почему решил написать? Потому что не нашел ни на хабре, ни в ру/еу сегменте интернета хорошего контента по данному вопросу.
Автор: KvendyZ