воскресенье, 15 декабря 2013 г.

Невероятно, но факт...

Вдруг обнаружил, что в Mapinfo 9.5, при использовании Windows 7 x64, команда  Mapbasic Timer() возвращает 0, всегда...

понедельник, 25 ноября 2013 г.

Советы шеф-повара: обновление данных в таблицах

Основная ценность, при работе практически с любыми программами, это данные. У программы, занимающейся работой с данными, должны присутствовать механизмы ввода, редактирования, сохранения данных.
В Mapinfo данные хранятся в таблицах и могут содержать две составляющие: графические и семантические данные. Со стороны Mapinfo, каждая таблица представляет собой нечто целое, содержащее некоторые записи, у каждой записи обязательно есть минимум одно семантическое поле. Со стороны файловой системы, таблица Mapinfo состоит из нескольких файлов, в каждом из которых содержится какая-то информация: семантика, графика, служебная информация, индексные файлы.
Сегодня я захотел написать о редактировании данных, так как это неотъемлемая часть процесса подготовки картографического материала. Ко всем прочему, в форумах регулярно возникают вопросы, связанные с "а как...?"

Я бы разделил возможности по редактированию на три группы:
1. ручное редактирование
2. полуавтоматизированное редактирование
3. автоматизированное редактирование

1. Ручное редактирование.
Дешево, надежно и практично. Графические объекты редактируются в окне карты, семантические поля - в окне списка или в окне информации. Хотел бы обратить внимание, что при редактировании таблиц, имеющих графические объекты (Mappable), через окно списка можно создавать записи без графических объектов. Это делается простым добавлением новой записи в окне списка. В последующем, прицепить к таким записям графические объекты, проблематично для неподготовленных пользователей. Если в такой таблице нужно добавить новый графический объект, но необходимо открыть эту таблицу в окне карты и нарисовать нужный графический объект.

2. Полуавтоматизированное редактирование.
Под полуавтоматизированным методом я понимаю редактирование с использованием
окна Mapbasic, построителя запросов и прочих штатных встроенных инструментов Mapinfo.
Для полноценного использования такого метода, на мой взгляд, нужны знания языка Mapbasic. Сложности в нем нет, но есть особенности версий, есть особенности Mapinfo, есть некоторые ограничения на использование Mapbasic в одноименном окне Mapinfo. Как я уже упоминал в ранних постах, документация Mapinfo и Mapbasic на очень хорошем уровне, и даже самостоятельное изучение не вызовет проблем.
В качестве живого примера полуавтоматизированного обновления приведу простой пример. Возникла элементарная и показательная задача по замене двойных кавычек на одинарные в поле таблицы.Хоть Mapbasic и довольно развитый язык, но, в основном, он содержит базовые(элементарные) функции. И строковой функции "ЗаменитьПодстроку" в нем нет. Зато есть огромное поле для фантазий по решению задачи с использованием ограниченного набора инструментов. Решение простое :-). Пара команд:

select * from SrcTable where InStr(1, SrcField, SrcSubstring) > 0 into TmpTable noselect

update TmpTable set SrcField = Mid$(SrcField, 1, InStr(1, SrcField, SrcSubstring) - 1) + NewSubString + Mid$(SrcField, InStr(1, SrcField, SrcSubstring) +Len(SrcSubstring) , 254)

Выполняем эту пару два раза получаем решенную задачу...

Первая команда select дает нам выборку записей исходной таблицы, в исходном поле которой есть требуемая для замены подстрока (в нашем случае - символ двойной кавычки ["]). В результате мы получаем запросную таблицу TmpTable. Теперь любые изменения в записях таблицы TmpTable автоматически записываются в соответствующие записи исходной таблицы SrcTable. Кто-то может спросить: а почему нельзя сразу написать update SrcTable ...?
Использование промежуточной таблицы обусловлено тем, что прямой update может вызвать ошибку, в случае если встретится запись, в которой в просматриваемом поле не искомой подстроки. Перехватывать ошибки в окне Mapbasic невозможно, поэтому используется промежуточная таблица.
  Вторая команда (update...) производит замену нашей SrcSubstring на NewSubString.
  Просто и быстро.
  Если надо произвести изменение графического объекта, то команда может выглядеть следующим образом:

update SrcTable set obj = ConvertToPLine(obj)
эта команда превратит все графические объекты в полилинии.

update SrcTable set obj = CreatePoint(x,y)
а эта команда создаст для каждой записи точечный объект, при условии что в таблице есть поля x и y с координатами.

3. Автоматизированное редактирование.
Под автоматизированным редактированием я понимаю использование специализированной программы на языке Mapbasic.
Это, пожалуй, универсальный метод, позволяющий реализовать все что душе угодно. С опытом, каждый для себя сможет сформулировать критерии, по которым можно принимать решение о выборе подхода, для решения вопроса о редактировании данных. Зачастую, написать пару команд в окне Mapbasic позволяет выполнить задачу быстрее, нежели подготовка самой простой программы на Mapbasic.
Простейшая программа для наших целей будет содержать всего две функции : обязательную main и пользовательскую, которая производит обработку строки.

sub main
  update TmpTable set SrcField = StringReplace(SrcField, SrcSubstring, NewSubString )
end sub

function StringReplace(byval aStr as string, byval aOldSub as string, byval aNewSub as string) as string
...
  StringReplace = ...
end function

Что мы имеем?
В коде присутствует обязательная для каждой программы Mapbasic sub main, в которой происходит обновление поля таблицы.
Функция StringReplace() производит обработку значения поля SrcField: заменяет все вхождения SrcSubstring на NewSubString.
Если нужна функция для обработки графических объектов, то ее объявление может иметь следующий вид

function ModifyObject(byval aObj as object) as object
...
  ModifyObject = ...
end function

В программе можно использовать все возможности Mapbasic. Остается откомпилировать текст программы при помощи компилятора Mapbasic и запускать ее на выполнение.

Вот, пожалуй, и все. Общая тема обозначена, все остальное - дело техники и опыта. Не бойтесь изучать, экспериментировать и думать.

вторник, 12 ноября 2013 г.

Экзотический рецепт использования Mapinfo.


В стародавние времена, когда стала проблескивать перспектива публикации геоданных в на просторах интернет, появилась задача быстренько смастерить прототип некой интернет страницы, на которой можно увидеть фрагмент карты Mapino, подготовленный на основании некоего семантического запроса...
На тот момент я еще только начинал осваивать Mapinfo, а в каком состоянии был MapXtreme сейчас я уже не припомню. В любом случае, времени на освоение новых технологий не было.
Итак, начнем с условия задачи.
Дано: некоторое количество однотипных рабочих наборов. семантическая БД с объектами, имеющими свое представление в одном из рабочих наборов. семантический объект, в зависимости от своего типа, располагается в определенной таблице рабочего набора.
Требуется: на некой web-странице, предоставить возможность выбора критериев поиска объекта и показать фрагмент соответствующего рабочего набора, с выделенным объектом, найденным в результате выполнения параметризованного поиска.
Исходя из имеющихся знаний и умений, мы с коллегой сошлись на "простом", в теоретическом плане, решении и организовали сервер приложений, который отвечал на запросы пользователей и взаимодействовал с MapInfo через COM-интерфейс.
Схема взаимодействия получилась такой:
Моя задача состояла в реализации взаимодействия с Mapinfo.
Основной проблемой явились однотипные рабочие наборы, а именно: невозможно открыть в Mapinfo две таблицы с одинаковым псевдонимом (alias).
Есть ли у Вас план, мистер Фикс?
Вот чем мне нравится разработка, так это то, что нет "правильных" и "неправильных" решений. Есть "работающие" или "не работающие" решения. Задачи можно решать разными способами, а это есть творчество, приносящее чувство глубокого удовлетворения. :-)
Придумалось оригинальное решение: каждый новый рабочий набор парсить и исправлять перед открытием в Mapinfo с целью присвоения всем таблицам рабочего набора уникальных псевдонимов. После этого, открывать рабочий набор и регистрировать информацию о нем, его открытых окнах и таблицах в специальных служебных таблицах. Все эти телодвижения нужны для того, чтобы знать в какой из таблиц производить поиск, какое из окон масштабировать по найденному объекту. Кроме этого, регистрация рабочего набора делается с целью предотвращения повторных открытий одного и того же файла.
После того как рабочий набор открыт, остаются сущие пустяки: найти объект по Идентификатору в нужной таблице нужного рабочего набора, масштабировать окно рабочего набора по найденному объекту и сохранить окно в графический файл.

В общем, оно заработало!!!
Честно скажу, что нет информации о тестировании под нагрузкой, но суть не в этом.
Сам процесс увлекает!

среда, 6 ноября 2013 г.

Швейцарский нож для Mapinfo.

Mapinfo имеет в своем распоряжении полный набор средств, для манипуляций с данными. Это и штатные инструменты, это и язык MapBasic, при помощи которого можно расширять функционал практически до бесконечности. Сам язык MapBasic довольно прост. Помимо родной документации вроде "MapBasic xxx UserGuide.pdf", есть книга «Программирование для MapInfo на примерах». Книга свежая, содержит много интересного и полезного, позволяющего начать движение в сторону освоения Mapinfo и MapBasic. Ко всему прочему, в Mapinfo есть крайне полезная, с практической точки зрения, вещь - "окно MapBasic". Когда это окно активно, в нем отображаются команды MapBasic, при помощи которых Mapinfo выполняет те или иные операции, например: открытие таблиц, отображение таблиц в виде карты или списка, команды по оформлению слоев карты и многое другое... Кроме отображения команд, "окно Mapbasic" служит для ввода и выполнения команд со стороны пользователя.

И вроде все хорошо, всего вроде хватает, но в один прекрасный момент появляется необходимость обработать много таблиц или рабочих наборов, и применить к ним однотипные действия. Конечно можно много поработать руками, но иногда приятно поработать головой, и освободить руки для более полезных и интересных дел. Вот так и родилась идея "швейцарского ножа" - инструмента, который поможет выполнять однотипные действия над таблицами Mapinfo и даже рабочими наборами.

Интерфейс "ножа" содержит элемент выбора рабочей папки (Искать в) в которой, с учетом вложенных папок, производится поиск файлов, согласно указанной в поле "файлы" маске.
Для каждого из найденных файлов выполняется "действие".
В качестве выполняемого "действия" над результатами поиска можно использовать произвольный модуль программы MapBasic или набор команд MapBasic


Индикатор в статусной панели отображает количество обработанных файлов.


Как это может быть полезно?
Например:
  • преобразовать кучу таблиц в формат mif/mid
  • обновить данные в полях таблиц(цы) рабочего набора




воскресенье, 20 октября 2013 г.

Бабушкин рецепт получения нужной точности координат в Mapinfo.

Когда-то давно, на заре моего освоения Mapinfo, кто-то из коллег обратил внимание на то, что при смене границ (Bounds) у таблицы, происходит изменение значений координат узлов фигур. Как следствие, происходило и изменение площади объекта.
Будучи человеком любопытным, я начал копать интернет на эту тему. Вот тогда я и  нашел чудный сайт  www.paris-pc-gis.com, зеркало которого располагается по новой ссылке. Помимо нужной мне информации, там было еще много чего вкусного и полезного.
Итак, вот что удалось выяснить.
Для внутреннего хранения и обработки координат, MapInfo использует внутреннюю виртуальную сетку, таким образом, как я понимаю, производится переход к целочисленной математике.
Ширина и высота границы таблицы делится на 2000000000 (2 миллиарда) и получается точность по каждому измерению, независимо от принятых единиц измерения длины.
Получаем простые формулы для получения точности по каждой координате:
Точность по X: dX = (MaxX - MinX)/2000000000
Точность по X: dY = (MaxY - MinY)/2000000000

При диапазоне карты 2000000 м по ширине, точность будет 1 мм.
При диапазоне карты 200000 м по ширине, точность будет 0,1 мм.

Рисунок, иллюстрирующий расположение объекта на "сетке" координат
 А вот что происходит с объектом при изменении границы таблицы.
Система координат исходной таблицы:
CoordSys NonEarth Units "m" Bounds (0, 0) (2000000000, 2000000000)
Система координат измененной таблицы:
CoordSys NonEarth Units "m" Bounds (0, 0) (2500000000, 2500000000).

Для просмотра информации об СК очень удобно использовать штатный инструмент из комплекта утилит Mapinfo "Coordsys Bound Manager" (в русской версии она называется "Границы рамки карты")
 А вот его интерфейс


Теперь координаты объектов всегда будут у вас под контролем.
Ссылка на файлы примеров

вторник, 15 октября 2013 г.

Индексы. А оно надо?

Продолжая тему индексов, я провел показательное тестирование влияния индексов на выполнение запросов к таблицам.
Тестовая таблица имеет порядка 400000 записей. По условию поиска выбиралась последняя запись в таблице.
Текст тестовой программы:
 Суть программы в следующем: делается циклический (1000 раз) выбор последней записи из большой таблицы. Для пущей нагрузки, перед выборкой записи производится переход на первую запись исходной таблицы. В первом проходе делалась обработка без индекса по поисковому полю SHAPE_GID, во втором - с построенным индексом.
Машинка, на которой делался тест достаточно шустрая, но это не очень важно, т.к. важны относительные показатели, а не абсолютные.
А вот и результаты...
Без индекса программа выполнялась примерно 16 минут (что составляет 960с).
С индексом все произошло за 2с.
Разница в скорости 960/2 = 480 раз.
Вот как-то так...

воскресенье, 13 октября 2013 г.

Индексы и как их готовить...

Активные пользователи Mapinfo могли сталкиваться с сообщениями
Файл индексов XXX создан для другого языка.


Такое сообщение появляется в том случае, если открываемая таблица проиндексирована в Mapinfo, языковая локализация которой, отличается от вашей. Т.е. если вы используете русифицированную Mapinfo и пытаетесь открыть какую-то таблицу, которая была проиндексирована в англоязычной версии Mapinfo, то вы получите подобное сообщение об ошибке. После пропуска сообщения, таблица остается открытой, но индексы деактивируются.
Языковой "проблеме" подвержены только индексы, построенные по символьным полям.

Проблема, вроде, не большая: как и сказано в сообщении Mapinfo, заходим в управление структурой таблицы и перестраиваем индекс. НО, у в управлении таблицей нас ждет сюрприз: информации о полях с индексами нет!!! (в общем, понятно, файл индексов отключен)

Чтобы перестроить индекс надо как-то узнать(вспомнить сообщения об индексах) имя необходимого поля и установить отметку индекса. Только после этого индекс перестроится. Кажется что не большая проблема. А если в таблице несколько индексов? А если таблиц много? Вот тут я вижу проблему.
Вторая проблема - невозможность программно отловить сообщение о несоответствии языка индекса.
Если мы напишем примерно такой код на MapBasic:
...
onerror goto err_trap
  open table rrr
  goto well_done
err_trap:
  resume well_done
well_done:
  ....
то мы не минуем появление сообщения о "языке" индекса.
Почему? Не знаю, но, вероятно, у разработчиков были веские причины для такой реализации, а может - "так получилось".
Теперь давайте посмотрим как организовано хранение информации об индексах для каждой таблицы Mapinfo. Напомню, что таблица Mapinfo хранит свои данные в разных таблицах:

  • <имя файла>.TAB. Этот файл содержит описание структуры данных таблицы. Он представляет из себя небольшой текстовый файл, описывающий формат того файла,который содержит данные.
  • <имя файла>.DAT или <имя файла>.WKS, .DBF, .XLS. Эти файл содержат табличные данные.
  • <имя файла>.MAP. Этот файл описывает графические объекты.
  • <имя файла>.IND содержит индексы полей таблицы.
Для примера создадим простую таблицу с индексами.

В файловой системе образуются следующие файлы:
Tab файл выглядит следующим образом:

Так что же делать пользователям, которые стали обладателями таблиц с индексами, построенными для других языков?
Выход 1: открывать таблицы и вручную перестраивать индексы.
Выход 2: любыми средствами массово удалить файлы *.ind в папках с обрабатываемыми таблицами и "исправить" описание структуры каждой таблицы в файлах *.tab.
Выход 3: обратится к автору и получить готовое лекарство, которое позволит произвести массовую обработку папок с таблицами и перестроить или удалить имеющиеся индексы.

воскресенье, 6 октября 2013 г.

Невероятно, но факт....

Однажды задумался о скорости файловых операций в Mapinfo.
Провел небольшой тест...
Текст программы и результаты на картинке. Время в секундах, потраченное на вывод в файл одинакового количества записей.
Вывод: открыть файл и много в него писать гораздо выгоднее, чем каждый раз открывать и закрывать файл. Но, если файл открывать/закрывать, то файл не блокируется средствами OS и можно просматривать его содержимое во время работы программы Mapbasic, которая делает вывод данных в файл.
В общем-то, Mapinfo тут не самый важный фактор, а основное время затрачивается на файловые операции средствами ОС.