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

преобразование проекций средствами ГИС Конструктор под ОС Astra-Linux v.1.3

Поиск  Пользователи  Правила  Войти
Форум » Linux » Средства разработки ГИС-приложений для Linux
Страницы: Пред. 1 2 3 4 5 6 7 След.
RSS
преобразование проекций средствами ГИС Конструктор под ОС Astra-Linux v.1.3, получение косой азимутальной равнопромежуточной проекции путём трансформации других проекций
 
Имелся в виду Шар, который может быть на базе любого эллипсоида (в смысле иметь радиус, равный большой полуоси).
Мы реализовали те формулы и проекции, которыми мы располагаем.
Если у Вас есть другие, то мы готовы их рассмотреть.
 
К сожалению, ГИС "Панорама-Мини" версия 11.12.3 не понимает формулировку " Шар ... на базе любого эллипсоида". Требуется указать конкретный тип эллипсоида из 48 возможных.



С какими из них азимутальная равнопромежуточная проекция Гума будет построена без "заворотов" и наложений изображения?

Что же касается формул, то как конечному потребителю, заплатившему деньги за программный продукт, меня интересует лишь конечный результат, а не то как его получить (это забота разработчиков). Пусть там заложены трижды правильные формулы, но если приложение не способно выдавать удобоваримые результаты, ему грошь цена. В частности, меня абсолютно не устраивает такая работа программы, когда половина проекции отображается верно, а вторая половина замазывает полученный результат, делая его малопригодным для дальнейшего использования.
Между тем, ввиду присутствия в файле mapcreat.h строки

AZIMUTHALOBLIQUE            = 7,  // Азимутальная равнопромежуточная косая

поддержка этого вида проекции в Конструкторе предполагалась.

Если же Вас интересует моё видение организации работы математики при расчёте косой азимутальной равнопромежуточной проекций, могу высказать два способа решения проблемы.

Первый. Это модернизация существующего механизма вычисления азимутальной равнопромежуточной проекций Гума (или модифицированной равнопромежуточной проекции) путём введения фильтрации объектов при нанесении их на карту. Следует вычислять расстояние (вдоль поверхности Земли) от каждого объекта до полюса проекции и, если оно превышает четверть длины Экватора, исключать их из отображения. Тем самым отображаться будет только половина полушария и эффекты "заворачивания" и наложения будут устранены.

Второй. Построить проекцию с нуля. На плоскости проекции строится полярная система координат (азимут, дальность). Для азимута нулевое направление - на Север, отсчёт по часовой стрелке.  Для дальности - отсчёт от центра в направлении азимута. Далее для каждого наносимого объекта вычисляются значения азимута (истинное направление на объект относительно направления на Север при нахождении в точке полюса проекции )и дальности (истинное расстояние от объекта до полюса проекции). С этими координатами объекты наносятся на плоскость проекции. Проекция, построенная таким способом, будет определена для всей поверхности Земли и лишена "заворотов".
 
1) Чтобы проекция была на произвольном шаре нужно выбрать тип эллипсоида - Пользовательский,
в параметрах эллипсоида в закладке датум в поле Большая полуось записать нужное значение (равное значению полуоси любого эллипсоида),
а в поле Полярное сжатие записать ноль.

2) Чтобы ограничить область отображения Вы можете на исходной карте (Карта мира цилиндрической проекции) нанести окружность с центром
будущей азимутальной проекции. Затем скопировать объекты с обрезанием по заданному объекту (окружности) на другую карту.
На промежуточную цилиндрическую или азимутальную.
В этом случае не будет заворачиваний объектов за горизонт.
Выполнение этой процедуры на лету при отображении в заданной проекции требует существенных временных затрат.
 
Складывается впечатление, что Вы совсем не тестируете создаваемые продукты.
Если в версии 11.12.3 проекции (азимутальная равнопромежуточная Гуам), хоть и неудобоваримые, но строятся в полном объёме вне зависимости от выбранного полюса проекции. Версия же 11.12.4, возможно, где-то и устраняет заворачивание краёв, но для определённых значений полюса формирует её не полностью. Насколько я успел заметить, для формирования этого типа проекций наиболее сложными являются случаи нахождения полюса проекции в районе географических полюсов, а также в районе меридиана 180 (-180). Вот как выглядит азимутальная равнопромежуточная проекция Гуам (элиипсоид: Шар на WGS 84), построенная разными версиями программы ГИС Панорама Мини

полюс проекции на Северном полюсе, долгота 180:



полюс проекции на Южном полюсе, долгота -180:



При таком раскладе механизм формирования проекции, реализованный в версии 11.12.3, в силу своей большей адекватности, видится более предпочтительным. По крайней мере, пусть и с помощью дополнительных манипуляций, он позволяет формировать проекции для любого района Земли, чего не скажешь о версии 11.12.4. Если процедуру устранения заворачивания краёв не получится отладить так, чтобы она не обрезала проекцию, лучше вернуться к версии 11.12.3.

Что же касается места, где процедура будет реализована, то где бы оно не находилось (непосредственно в процедурах формирования проекции или в самостоятельно написанных функциях фильтрации объектов перед запуском подобных процедур), в любом случае это будет выполняться "на лету" с необходимым в подобных случаях увеличением временных затрат. Для косых азимутальных проекций этого избежать нельзя, ибо до того, как станут известны координаты полюса проекции, просчитать заранее вид проекции невозможно. Для каждого нового положения полюса проекции требуется новый просчёт проекции. И это никак не обойти. Поэтому бессмысленно экономить на времени выполнения процедуры формирования проекции, если при этом получается не конечная проекция, а только полуфабрикат. А, чтобы довести его до кондиции, требуются дополнительные преобразования исходного материала, сводящие на нет всю экономию времени.
Поэтому рациональнее сразу выполнить все необходимые просчёты в ходе формирования проекции и на выходе получать результат, не требующий дополнительных обработок.
 
Хорошо. Обрезку пока отключим.
 
Хорошо. Ожидаем появления в ГИС конструкторе поддержки модифицированной азимутальной равнопромежуточной и азимутальная равнопромежуточной Гуам (в том виде, как это реализовано в ГИС Панорама Мини v.11.12.3).

Теперь вопросы о программной реализации процесса построения проекций.
В Вашем сообщении по текущей теме от 30.09.2014 10:10:00 приведена ссылка на раздел  4.2.24 руководства программиста ("Копирование объектов на другую карту с изменением системы координат"). В данном разделе приведён фрагмент кода, позволяющего выполнять копирование объектов для создания карты в новой проекции:

int listcount = mapGetSiteListCount(hMap, hSite);
for (int list = 1; list < listcount; list++)
{
  int objectcount = mapGetSiteObjectCountInList(Map, hSite, list);
  for (int object = 1; object < objectcount; object++)
  {
      // Чтение объекта
      if (mapReadObjectByNumber(hMap, hSite, hObj, list, number) == hObj)
         {
            // Перенос объекта на другую карту (hMap может не меняться)
            if (mapChangeObjectMap(hObj, hMapNew, hSiteNew) != 0)
               {
                  // Запись на новую карту (для нарезки по листам - mapCommitWithPlace)  
                  mapCommitObject(hObj);
                }
          }
  }
}

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

for (int object = 1; object <= objectcount; object++)   // иначе карта из 1 листа не будет обрабатываться

и  

for (int object = 1; object <= objectcount; object++)  //иначе не будет обработан последний объект.


Далее затруднение вызвало использование функции mapReadObjectByNumber(...). Согласно её описанию в seekapi.h данная функция не возвращает значение типа HOBJ. При успешном выполнении она возвращает значение 2, при ошибке 0. Попробовал вместо неё использовать функцию mapReadObjectByNumberEx(...), которая при успешном выполнении должна возвращать объект. Но, что при работе первой, что при работе второй функции они обе упорно возвращают ноль (т.е. ошибку).
Т.е. в моём случае значение  objectcount определяется как 28603, значение listcount как 1 (исходная карта открыта и на ней обнаружено 28603 объекта). Но далее цикл чтения по номеру объекта повторяется 28603 раза и для всех номеров объектов возвращается значение 0. Результат одинаков что при использовании функции mapReadObjectByNumber(...), что при использовании mapReadObjectByNumberEx(...).

Подскажите, что ещё может быть неправильно в коде и как его следует изменить для правильного выполнения чтения объектов карты?
Изменено: Алексей Агулов - 28.11.2014 11:51:26
 
С замечанием про последний объект и лист согласен. Пример поправим. Должны стоять знаки "<=".

mapReadObjectByNumber возвращает значение параметра info (HOBJ) при успешном выполнении.
Ноль возвращается при ошибочных параметрах. Например, не создан HOBJ. Нужно видеть Ваш текст.

Код
 // Выбор объекта по номеру листа и последовательному номеру объекта
 // (прямой доступ к объекту без перебора)
 // hMap     - идентификатор открытой карты,
 // hSite    - идентификатор открытой пользовательской карты,
 // info     - идентификатор существующего объекта,
 //            в котором будет размещен результат поиска;
 // list     - номер листа (для пользовательской карты всегда 1);
 // object   - последовательный номер объекта в листе
 // (начиная с 1 до mapGetObjectCount(...) или mapGetSiteObjectCount(...)).
 // Если объект имеет признак "удален" - возвращает 1 !!!
 // При успешном выполнении возвращает значение info.
 // При ошибке возвращает ноль

_MAPIMP HOBJ _MAPAPI mapReadObjectByNumber(HMAP hMap, HSITE hSite, HOBJ info,
                                           long int list, long int object);

 // Если объект имеет признак "удален", то функция возвращает 1.
 // При успешном выполнении возвращает значение 2.
 // При ошибке возвращает ноль

_MAPIMP long int _MAPAPI mapReadObjectByNumberEx(HMAP hMap, HSITE hSite, HOBJ info,
                                                 long int list, long int object);



Вот пример из SDK чтения данных:

Код
  int listcount = mapGetListCount(hMap);

  HOBJ hObj = mapCreateSiteObject(hMap, hMap);

  SYSTEMTIME data;
  GetSystemTime(&data);

  int start = (long)data.wSecond + (long)data.wMinute*60L + (long)data.wHour*3600L;

  for (int r = 0; r < 10; r++)
  {
    for (int i = 1; i <= listcount; i++)
    {
      int objectcount = mapGetObjectCount(hMap, i);

      for (int j = 1; j <= objectcount; j++)
      {
         mapReadObjectByNumber(hMap, hMap, hObj, i, j);
      }
    }
  }

  GetSystemTime(&data);

  int end = (long)data.wSecond + (long)data.wMinute*60L + (long)data.wHour*3600L;

  end = end - start;

  char message[200];
  sprintf(message, "Операция заняла - %u секунд для 10 итераций", end);
  ::MessageBox(handle, message, "Тестирование производительности", MB_OK | MB_TASKMODAL);

  mapFreeObject(hObj);
 
Спасибо. Пример из SDK помог. С чтением объектов карты проблема решена.

Теперь вопрос с записью на новую карту.
Вот мой код:

Код
            

        HMAP hMap = mapOpenData("k1.map",0);  //карта в цилиндрической проекции

        MAPREGISTEREX mapreg;
   LISTREGISTER  listreg;
   memset((void*)&mapreg, 0, sizeof(mapreg));
   memset((void*)&listreg, 0, sizeof(listreg));
   mapreg.Length = sizeof(MAPREGISTEREX);
   listreg.Length = sizeof(LISTREGISTER);

   mapRegisterFromMapType(GEOGRAPHIC, &mapreg);
   mapreg.EllipsoideKind = SPHERE_WGS_84;
   mapreg.MaterialProjection = LAMBERTOBLIQUEAZIMUTHAL; // азимутальная равновеликая Лпмберта
   mapreg.MainPointParallel = 50 * M_PI / 180.0; // широта полюса проекции 50 градусов
   mapreg.AxisMeridian = 90 * M_PI / 180.0; // долгота полюса проекции 90 градусов

   // Данные о проекции заполнены
   mapreg.DataProjection = 1;

   // Создать новую карту с классификатором Karta_mira.rsc
   HMAP hMapNew = mapCreateMapEx("MyMap.map", "Karta_mira.rsc", &mapreg, &listreg);

   // Создать пользовательску карту и добавить в документ
   HSITE hSiteNew = mapCreateAndAppendTempSite(hMapNew, "Karta_mira.rsc");

   int listcount = mapGetListCount(hMap);
   HOBJ hObj = mapCreateSiteObject(hMap, hMap);

   for (int i = 1; i <= listcount; i++)
   {
       int objectcount = mapGetObjectCount(hMap, i);
 
       for (int j = 1; j <= objectcount; j++)
       {
           if (mapReadObjectByNumber(hMap, hMap, hObj, i, j) == hObj)
           {
                      // Перенос объекта на другую карту 
               if (mapChangeObjectMap(hObj, hMapNew, hSiteNew) != 0)
               {
                   // Запись на новую карту 
                   mapCommitObject(hObj);
               }
           }
       }
   }

   mapFreeObject(hObj);

   // Закрыть и удалить временную карту
   mapCloseSiteForMap(hMapNew, hSiteNew);



Т.е. открывается исходная карта в цилиндрической проекции, создаётся новая в азимутальной и затем объекты из первой карты копируются во вторую.
В результате выполнения этого кода в папке приложения формируются три файла: MyMap.dat, MyMap.hdr и MyMap.map (файл MyMap.sem отсутствует). Но после завершения работы приложения при открытии карты (MyMap.map) объекты на ней отсутствуют.
Возможно, причина в неправильной подготовке структур MAPREGISTEREX и LISTREGISTER. В большей мере, наверное, это относится к структуре LISTREGISTER. Как её заполнить, если требуется проекция в составе 1 листа, содержащая изображение всей Земли? Допустим ли такой вариант?:
Код

strcpy(listreg.ListName, "Лист 1");
       strcpy(listreg.FileName, "MyMap.map");
       listreg.BNorthEastCoordinate = M_PI/2;
       listreg.BNorthWestCoordinate = M_PI/2;
       listreg.BSouthEastCoordinate = -M_PI/2;
       listreg.BSouthWestCoordinate = -M_PI/2;
       listreg.LNorthEastCoordinate = -M_PI;
       listreg.LNorthWestCoordinate = M_PI;
       listreg.LSouthEastCoordinate = -M_PI;
       listreg.LSouthWestCoordinate = M_PI;


Помогите разобраться.
Изменено: Алексей Агулов - 01.12.2014 15:13:15
 
Это лишнее действие - mapCreateAndAppendTempSite и mapCloseSiteForMap. Временная карта сама удаляется вместе с объектами.

А перенос выглядит так:

mapChangeObjectMap(hObj, hMapNew, hMapNew);
 
Спасибо.
Код поправил. Всё заработало.

Теперь проблема следующего характера.
Мне была выслана новая версия ГИС Конструктора с поддержкой двух новых азимутальных проекций.
Мой код для задания вида проекции на новой карте выглядит так:
Код

mapRegisterFromMapType(GEOGRAPHIC, &mapreg);
mapreg.EllipsoideKind = SPHERE_WGS_84;
mapreg.MaterialProjection =  MODIFIEDAZIMUTALEQUIDISTANT; //AZIMUTALEQUIDISTANTGUAM;
mapreg.MainPointParallel = 89 * M_PI / 180.0;
mapreg.AxisMeridian = 0 * M_PI / 180.0;



При выборе в качестве типа проекции значения AZIMUTALEQUIDISTANTGUAM проекция не формируется (т.е. после открытия полученной карты в приложении Панорама Мини отображается только серое поле без объектов, хотя в информационной строке сообщается, что открыто 31383 объектов.
При выборе MODIFIEDAZIMUTALEQUIDISTANT проекция формируется, но только на четверть:



При этом само приложение Панорама Мини v.11.12.3 выполняет построение проекции при тех же параметрах корректно:




В чём может быть причина? В моём коде или в неправильном переносе механизма построения проекции из Панорама Мини в ГИС Конструктор?
Изменено: Алексей Агулов - 22.01.2015 11:15:25
Страницы: Пред. 1 2 3 4 5 6 7 След.
Читают тему (гостей: 1)



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

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