На главную... Продукты | Технологии | Классификаторы | Проекты | Скачать | Цены| Форум | Статьи | Обучение | Контакты

Скорость отрисовки карты (поддержка Level of Detail и фильтр по площади/длине объекта)

Поиск  Пользователи  Правила  Войти
Форум » Настольные приложения » GIS ToolKit, GIS ToolKit Active, ГИС Конструктор для Windows
Страницы: 1
RSS
Скорость отрисовки карты (поддержка Level of Detail и фильтр по площади/длине объекта)
 
Добрый день.

Являемся обладателями лицензии на инструментарий GisToolkit Free 12, но не используем компонентов RAD Studio, поскольку работаем исключительно в Visual Studio. По этой причине отображаем карту в нашем приложении в "рукопашную", используя напрямую API библиотек gisu64acces.dll и gisu64vecex.dll.

Мы  имеем большую карту, порядка 3000 x 3000 км. На мелких масштабах карта  довольно сильно подтормаживает, не смотря на то, что я разгружал слои, и  ни чего лишнего на карте нет. На мелких масштабах отображаются только леса, водоемы (площадные  объекты) и крупные шоссе.
Воспользовавшись поиском по форуму, я понял, что проблема по поводу скорости отрисовки карты уже неоднократно поднималась.

Список стандартных рецептов таков (возможно, я что-то упустил):

  • разгрузка карты по масштабом (настройка видимости слоев по масштабам в классификаторе)
  • разбивка карты на листы
  • использование растров rsw
  • использование gis web server (нам не подходит)
  • сжатие карты методом округления координат
но, проанализировав предложенные рецепты, у меня появились сомнения, что они мне помогут, разве что может быть мне поможет "Сжатие карты методом округления координат", но я не могу его проверить, т.к. имею лицензию только на GisToolkit Free.
Скажите, пожалуйста, данная функция доступна только в приложении Профессиональная ГИС Карта? Или имея лицензию на GisToolkit Free можно так же воспользоваться данным функционалом через какой то инструмент? Этот же вопрос касается и разбивки карты на листы.

Как я уже говорил выше, разгрузку карты я проводил, на ней нет ни чего лишнего, разве что довольно большое количество мелких водоемов, отфильтровать которые нет возможности, либо я не обладаю информацией как это сделать. У меня все площадные водоемы лежат в одном слое.
Думаю,  что проблема в том, что полигоны лесов и водоемов не имеют уровней  детализации (LOD) под разные масштабы, и на мелких масштабах в полигонах  излишне много точек. Существуют ли какой то инструментарий, который  позволит "упростить" полигоны для мелких масштабов и "включать"  отображение упрощенных полигонов на определенной линейке масштабов,  отключая детальные? Такой подход может сильно ускорить отображение  карты, но естественно увеличит ее размер на диске, что для нас не  является проблемой. Или такой метод можно применить только вручную  написав инструмент, который, например, заэкспортит нужные слои в shape  файл, потом изготовит линейку LOD, после чего можно будет добавить их в  качестве отдельных слоев и настроить видимость в классификаторе по  масштабам? Выглядит это довольно трудоемко, но по идее должно решить  проблему. Как всегда лень заставляет хотеть какой то автоматический  инструмент и волшебную кнопку "Сделать хорошо!" :)

По поводу использования растров RSW - т.к. карта большая, то изготовить растры для всей линейки масштабов не получится, по причине их огромного объема. Не знаю можно ли каким то образом сделать гибридную карту, в которой на мелких масштабах вместо векторной карты будет отображаться растровая. Если это можно, напишите, пожалуйста как это сделать средствами MAPAPI. Правда я сразу вижу еще одну проблему с растрами. У нас должен быть функционал управления видимостью определенного набора слоев. Пользователь может сам отключать отображение водоемов/надписей/растительности/дорог и т.п. Делаю я это через запросы HSELECT, mapSelectLayer, mapSetViewSelect.

Итого список моих вопросов таков:

  1. Функция "Сжатие карты методом округления координат" имеется только в приложении Профессиональная ГИС Карта? И имея довольно дорогостоящую лицензию на GisToolkit Free придется покупать не менее дорогостоящую лицензию на приложение Профессиональная ГИС Карта? И, к сожалению, не факт что эта функция поможет.
  2. Аналогичный вопрос по поводу разбивки карты на листы. Думаю, что это  тоже вряд ли поможет, т.к. на мелких масштабах в окно будут попадать  почти все листы карты
  3. Имеется ли какой либо инструмент, позволяющий отфильтровать отображение площадных объектов малой площади на мелких масштабах. Проблема в том, что есть один слой "воды", в котором имеются как крупные водоемы, так и мелкие. (тоже самое касается линейных объектов малой длины)
  4. Вопрос по поводу возможности использования уровней детализации для объектов в зависимости от текущего масштаба
  5. Можно ли каким то образом отображать гибридную карту средствами MAPAPI (векторная для крупных масштабов, RSW растры для мелких)
 
1. Функция "Сжатие карты методом округления координат" на самом деле работает в режиме Сортировка карты, которую можно вызвать в виде диалога или в темную:
 // Сортировка отдельной карты документа
 //  mapname - сортируемая карта
 //  flags   - Флажки обработки карты :
 //   0 - сортировать все листы,
 //   1 - только несортированные,
 //   2 - сохранять файлы отката,
 //   4 - повысить точность хранения,
 //   8 - нормальная точность хранения (FLOAT).
 //  16 - повысить точность хранения, формат - см
 //  32 - повысить точность хранения, формат - мм
 //  64 - повысить точность хранения, формат - радианы
 // hEvent - адрес функции обратного вызова для уведомлении о процессе
 // eventparam - параметры функции обратного вызова
 // outpath - адрес строки для записи нового пути к отсортированной карте,
 //           если адрес строки не задан, то карта обновляется на месте
 // size    - размер строки для записи пути
 // При ошибке возвращает ноль

_MAPIMP long int _MAPAPI MapSortingWithEvent(const char *mapname,
                                            long int flags,
                                            EVENTCALL hEvent,
                                            void *eventparam,
                                            char *outpath,
                                            long int size);
2. Далее вам необходимо настроить масштабы отображения объектов (видимость) в классификаторе. Такие объекты не будут отображаться и для них не будет считываться метрика при отображении

3. Можно сделать гибрид (разделить объекты на отдельные карты, сделать растры), как вы предлагаете и самим управлять составом карт через

 // Добавить данные к открытой карте (карту, растр, матрицу)
 // hMap -  идентификатор открытых данных
 // name - имя открываемого файла (SIT, MTW, MTQ, RSW, MPT)
 // mode - режим чтения/записи (GENERIC_READ, GENERIC_WRITE или 0)
 // Возвращает идентификатор типа данных (FILE_MAP - для пользовательской
 // карты, FILE_RSW - для растра, FILE_MTW - для матрицы, FILE_MTL - для
 // матрицы слоев, FILE_MTQ - для матрицы качеств), данные добавляются в
 // список последними, если данные уже были открыты, число открытых данных
 // (карт, растров, матриц) не меняется
 // transform - признак трансформирования пользовательской карты
 //             к ранее открытым данным (если проекции разные):
 //             0 - не трансформировать данные (преобразовывать "на лету"),
 //             1 - трансформировать данные при открытии и сохранить карту
 //                 в новой проекции,
 //            -1 - задать вопрос пользователю.
 // В серверной версии (-1) обрабатывается, как 0.
 // При ошибке возвращает ноль

_MAPIMP long int _MAPAPI mapAppendData(HMAP hMap, const char *name,
                                      long int mode = 0);

_MAPIMP long int _MAPAPI mapAppendDataEx(HMAP hMap, const char *name,
                                        long int mode = 0,
                                        long int transform = -1);

 // Добавить данные к открытой карте (карту, растр, матрицу)
 // hMap -  идентификатор открытых данных
 // name - имя открываемого файла (SITX, SIT, MTW, MTQ, RSW, MPT) в кодировке UNICODE
 // mode - режим чтения/записи (GENERIC_READ, GENERIC_WRITE или 0)
 // transform - признак трансформирования пользовательской карты
 //             к ранее открытым данным (если проекции разные):
 //             0 - не трансформировать данные (преобразовывать "на лету"),
 //             1 - трансформировать данные при открытии и сохранить карту
 //                 в новой проекции,
 //            -1 - задать вопрос пользователю.
 // В серверной версии (-1) обрабатывается, как 0.
 // password - пароль доступа к данным из которого формируется 256-битный код
 //            для шифрования данных (при утрате данные не восстанавливаются)
 // size     - длина пароля в байтах !!!
 // Передача пароля необходима, если при создании карты он был указан.
 // Если пароль не передан, а он был указан при создании,
 // то автоматически вызывается диалог scnGetMapPassword из mapscena.dll (gisdlgs.dll)
 // Если выдача сообщений запрещена (mapIsMessageEnable()), то диалог
 // не вызывается, а при отсутствии пароля происходит отказ открытия данных
 // Возвращает идентификатор типа данных (FILE_MAP - для пользовательской
 // карты, FILE_RSW - для растра, FILE_MTW - для матрицы, FILE_MTL - для
 // матрицы слоев, FILE_MTQ - для матрицы качеств), данные добавляются в
 // список последними, если данные уже были открыты, число открытых данных
 // (карт, растров, матриц) не меняется
 // При ошибке возвращает ноль

_MAPIMP long int _MAPAPI mapAppendAnyData(HMAP hMap, const WCHAR *name,
                                         long int mode = 0, long int transform = -1);

_MAPIMP long int _MAPAPI mapAppendDataUn(HMAP hMap, const WCHAR *name,
                                        long int mode = 0);

4. А какой объем в Гб занимают данные, и что значит тормозит?

5. Хотя бы один экземпляр ГИС Панорама на компанию для работы с картами и т.п. желательно приобрести.
 
Здравствуйте!

Сжатие координат до см пробовал (в режиме сортировки карты) - на производительность отрисовки не повлияло.

Гибридный режим еще не успел попробовать, попробую чуть позже.

Цитата
Andrey Gheleznyakov написал:

4. А какой объем в Гб занимают данные, и что значит тормозит?

Если перемещать карту в каком то направлении или вращать ее по курсу с помощью mapSetupTurn, то прорисовка карты выполняется с сильно заметным дискретом (очень мало кадров в секунду).

К слову сказать на компьютере установлено очень неплохое железо:

Intel Core i7-7700 3.6 GHz
32 GB RAM
SSD

Карта весит порядка 700 Мегабайт. Могу ее выложить на FTP и дать вам ссылку на почту, если это необходимо. Вышлете мне e-mail.
 
С таким железом она просто летать должна, так как мы ее с диска один раз считаем. Возможно дело в классификаторе условных знаков. Может там сложная векторная заливка площадных объектов используется (например, один клиент использовал заливку площадными значками, а объект на пол России и таких значков при 10 точках метрики получается 20 миллионов). адрес почты: gisga@yandex.ru
 
Отправил
 
Цитата
Итого список моих вопросов таков:

 Функция "Сжатие карты методом округления координат" имеется только в приложении Профессиональная ГИС Карта? И имея довольно дорогостоящую лицензию на GisToolkit Free придется покупать не менее дорогостоящую лицензию на приложение Профессиональная ГИС Карта? И, к сожалению, не факт что эта функция поможет.
 Аналогичный вопрос по поводу разбивки карты на листы. Думаю, что это  тоже вряд ли поможет, т.к. на мелких масштабах в окно будут попадать  почти все листы карты
 Имеется ли какой либо инструмент, позволяющий отфильтровать отображение площадных объектов малой площади на мелких масштабах. Проблема в том, что есть один слой "воды", в котором имеются как крупные водоемы, так и мелкие. (тоже самое касается линейных объектов малой длины)
 Вопрос по поводу возможности использования уровней детализации для объектов в зависимости от текущего масштаба
 Можно ли каким то образом отображать гибридную карту средствами MAPAPI (векторная для крупных масштабов, RSW растры для мелких)

1) Процедура сжатия имеет такой вид:
Код
  // Создать поддиректорию
  WCHAR newpath[MAX_PATH_LONG];
  WcsCopy(newpath, mapname, sizeof(newpath));

#ifdef WIN32API
  WcsCat(newpath, L".Mini\\", sizeof(newpath));
#else
  WcsCat(newpath, L".Mini/", sizeof(newpath));
#endif

  // Создать поддиректорию для копии
  if (CreateTheDirectory(newpath) == 0)
    {
      mapErrorMessageUn(IDS_CREATE, newpath);
      return 0;
    }

  SHFILEOPSTRUCTW lpFileOp;
  memset((void*)&lpFileOp, 0, sizeof(lpFileOp));

  WCHAR PathDeleted[MAX_PATH_LONG];
  WcsCopy(PathDeleted, newpath, sizeof(PathDeleted));
  WcsCat(PathDeleted, L"*.*\0\0", sizeof(PathDeleted));
  lpFileOp.hwnd   = 0;
  lpFileOp.wFunc  = FO_DELETE;
  lpFileOp.pFrom  = PathDeleted;
  lpFileOp.fAnyOperationsAborted = false;
  lpFileOp.fFlags = FOF_FILESONLY|FOF_SIMPLEPROGRESS|FOF_NOCONFIRMATION    ;

  // Очистить новую папку
  SHFileOperationW(&lpFileOp);

  WcsCopy(PathDeleted, newpath, sizeof(PathDeleted));
  WcsCat(PathDeleted, L"Log\\*.*\0\0", sizeof(PathDeleted));

  // Очистить новую папку
  SHFileOperationW(&lpFileOp);

  WCHAR newname[MAX_PATH_LONG];
  WCHAR newext[MAX_PATH_LONG];
  SplitThePath(mapname, NULL, NULL, newname, newext);

  WcsCat(newpath, newname, sizeof(newpath));
  WcsCat(newpath, newext, sizeof(newpath));

  if (mapCopyMapUn(mapname, newpath) == 0)
    {
      mapErrorMessageUn(IDS_WRITE, newpath);
      return 0;
    }

  // Открыть входную карту в папке Mini
  HMAP hMap = mapOpenDataUn(newpath);
  if (hMap == 0) return 0;

  int israd = mapIsSiteRealGeo(hMap, hMap);
  if (israd)
    {
      // Отсортировать листы карты в нормальной точности - в метрах
      MapSortingSitePro(hMap, hMap, 8, handle, 0, 0, 0);   
    } 

  mapLogAccess(hMap, hMap, 0);

  // Установить точность хранения в сантиметрах (long int)
  mapSetMapPrecisionMini(hMap);

  if (mapGetMapAccessLanguage() == ML_RUSSIAN)
    {
       mapMessageToLog(hMap, hMap,
                       "Выполнено сжатие данных методом округления координат", MT_WARNING);
    }
  else
    {
       mapMessageToLog(hMap, hMap,
                       "Coordinates of objects are compressed and approximated", MT_WARNING);
    }

  HOBJ hObj = mapCreateObject(hMap);
 
  int listcount = mapGetListCount(hMap);
     
  // Отправить в диалог сообщение о начале обработки
  if (handle)
    {
#ifdef WIN32API
      ::SendMessage(handle, WM_LIST, listcount, 0);
#else
      MessageHandler(0, WM_LIST, listcount, 0, 0);
#endif
    }

  // Перейти к целым числам  
  for (int list = 1; list <= listcount; list++)
  {
    if (list > 1)
      {
        // Закрыть предыдущий лист для экономии памяти и надежности обработки
        mapCloseList(hMap, list-1); 
      }

    // Отправить в диалог сообщение о смене текущего листа
    if (handle)
      {
#ifdef WIN32API
        if (::SendMessage(handle,WM_LIST,listcount,list) == WM_LIST)
#else
        if (MessageHandler(0, WM_LIST, listcount, list, 0) == WM_LIST)
#endif
          break;
      }

    // Переписать объекты
    int objcount = mapGetObjectCount(hMap, list);
    if (objcount == 0) continue;

    // Объектов на 1 процент
    double percentObject = (double)objcount/100;

    // Процент записанных объектов
    int percent = 0;

    int kind = IDLONG2;

    for (int j = 1; j <= objcount; j++)
    {
      if (mapReadObjectByNumber(hMap, hMap, hObj, list, j) != hObj)
        {
          // Пропускать удаленные объекты
          continue;
        }

      mapSetObjectKind(hObj, kind);

      // Выровнять записи семантики
      mapAlignSemantic(hObj);

      mapCommitObject(hObj);

      // - Отправить в диалог сообщение о изменении состояния обработки объектов
      int k = percent;
      percent = (int)((double)j/percentObject);
      if ((k != percent) && (handle != 0))
        {
#ifdef WIN32API
          if (::SendMessage(handle,WM_OBJECT,percent,list) == WM_OBJECT)
#else
          if (MessageHandler(0, WM_OBJECT, percent, list, 0) == WM_OBJECT)
#endif
            {
              list = listcount + 1;
              break;
            }
        }
    }

   if (handle != 0)
     {
#ifdef WIN32API
       if (::SendMessage(handle,WM_OBJECT,100,list) == WM_OBJECT)
#else
       if (MessageHandler(0, WM_OBJECT, 100, list, 0) == WM_OBJECT)
#endif
         {
           break;
         }
     }
  }

#ifdef WIN32API
  if (handle)
    {
      WCHAR Text[MAX_PATH_LONG];
      if (mapGetMapAccessLanguage() == ML_ENGLISH)
        {
          WcsCopy(Text, L"Sorting: ", sizeof(Text));
        }
      else
        {
          WcsCopy(Text, L"Сортировка: ", sizeof(Text));
        }

      mapPathToShortUn(newpath, Text + wcslen(Text), 30);
      ::SetWindowTextW(handle, Text);
    }
#endif

  // Отсортировать листы карты
  if (handle)
    {
#ifdef WIN32API
      ::SendMessage(handle, WM_LIST, -1, 0);
#else
      MessageHandler(0, WM_LIST, -1, 0, 0);
#endif
    }

  MapSortingSitePro(hMap, hMap, 0x590, handle, 0, 0, 0);  // Спецсообщения

  // Отправить в диалог сообщение о завершении обработки
  if (handle)
    {
#ifdef WIN32API  
      ::SendMessage(handle,WM_LIST,listcount,listcount);
#else
      MessageHandler(0, WM_LIST, listcount, listcount, 0);
#endif
    }     

#ifdef WIN32API
  if (handle)
    {
      WCHAR * Text;
      if (mapGetMapAccessLanguage() == ML_ENGLISH)
        {
          Text = L"Approximation coordinates";
        }
      else
        {
          Text = L"Сжатие методом округления координат";
        }

      ::SetWindowTextW(handle, Text);
    }
#endif

  // Освободить ресурсы
  mapFreeObject(hObj);
  mapCloseData(hMap);

2) Разбивка на листы нужна для ускорения при увеличении картинки, а не при сжатии.
3) Функции фильтрации метрики есть в программном интерфейсе и их можно применить аналогично процедуре сжатия (вставить в обработку объектов в цикле).

Обычный подход заключается в том, что на один-два соседних более мелких масштаба (сжатие в 2-4 раза) достаточно настройки границ видимости объектов,
чтобы разрядить картинку. Дальше лучше перейти к другой карте.
Карты могут быть собраны в MPT-проект, в котором каждая карта имеет свои границы видимости (диапазон масштабов).
При сжатии карты незаметно переходим к разгруженной карте для более мелкого масштаба. В ней может быть отфильтрована метрика.
По заданному размеру площади полигонов и длинам линейных объектов выполняется выделение и удаление мелких объектов и так далее.
Это называется процедурой генерализации, которая может быть выполнена в ГИС Панорама 12 (или ГИС Карта 2011).
Можно написать подобные функции и на основе MAPAPI.
 
С учетом данных представленных по почте есть еще одна рекомендация.

Отображение карты России в масштабе 1 : 10 000 000, сформированной из данных OpenStreetMap и детализированной условно для масштаба 1: 10 000,
не может быть быстрым.
Есть карты масштаба 1: 1 000 000, 1: 5 000 000, которые будут отображаться адекватно.
Если их еще поделить на листы и сжать, то Вы получите 10-20 кадров в секунду из векторного изображения.
Генерализация карты для сжатия в 1 000 раз не имеет смысла. Переходы делают в 2-4 раза с профессиональной подготовкой.
 
Спасибо за советы. На этой неделе будем пробовать что-то сделать с нашей картой.
Страницы: 1
Читают тему (гостей: 1)



© КБ Панорама, 1991-2024

Регистрируясь или авторизуясь на форуме, Вы соглашаетесь с Политикой конфиденциальности