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

[MAPAPI] Рамка отображаемого знака объекта

Поиск  Пользователи  Правила  Войти
Форум » Linux » Средства разработки ГИС-приложений для Linux
Страницы: 1 2 След.
RSS
[MAPAPI] Рамка отображаемого знака объекта, [MAPAPI] Рамка отображаемого знака объекта не пересчитывается при изменении масштаба
 
Здравствуйте.

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

Реализовал, результат меня не удовлетворил, потому-что рамка объекта после его создания не меняется.
Как я понял, рамка объекта (ObjectViewFrame) вычисляет один раз и таким образом , чтобы при любом масштабе

и любом повороте векторного объекта знак векторного объекта гаранитрованно вместился в рассчитанную рамку.

Пример.
Создаю векторный объект,  и линейный объект для отображения рамки, меняю масштаб карты.
(Местами используются namespace panorama:: - можно удалить, gis::coord::GisCoord::init()/deinit() - для указания путей к epsg файлам, а так почти на чистом mapapi пример получился).

Код
//карта из пакета gisdesigner с сайта
#define MAP_PATH "/home/vegorov/testsMaps/map/Podolsk/Podolsk.map"


//классификатор из пакета gisdesigner с сайта
#define RSC_PATH "/usr/share/gisdesigner/examples/Data/RSC/operator.rsc"


#define SQUAD_OBJ_KEY "312614004007" //векторный объект
#define BORDER_OBJ_KEY "111045000331" //красная жирная линия


void drawToFile(HMAP hmap, const char* filePath, int w, int h){
    XIMAGEDESC ximage;
    ximage.Depth = 16;
    ximage.CellSize = 2;
    //подбираем размеры как степени двойки
    ximage.Width = w;
    ximage.Height = h;
    ximage.RowSize = ximage.Width * ximage.CellSize;
    size_t bytesCount = ximage.Width * ximage.Height *
                     ximage.CellSize;
    ximage.Point = new char[bytesCount];
    ximage.Point = static_cast<char*>(
               memset(static_cast<void*>(ximage.Point), 0, bytesCount));
    DFRAME mapFrame;
    long rc = mapGetTotalBorder(hmap, &mapFrame, panorama::PP_PICTURE);
    if (rc == 0){
        std::cerr << "can not get border of map" << std::endl;
        delete []ximage.Point;
        std::exit(1);
    }
    int centerX = static_cast<int>((mapFrame.X1 + mapFrame.X2)/2.0);
    int centerY = static_cast<int>((mapFrame.Y1 + mapFrame.Y2)/2.0);
    QRect drawRect(QPoint(), QSize(w, h));
    drawRect.moveCenter(QPoint(centerX, centerY));
    RECT rect;
    rect.top = drawRect.top();
    rect.bottom = drawRect.top() + h;
    rect.left = drawRect.left();
    rect.right = drawRect.right() + w;
    rc = mapPaintToXImage(hmap, &ximage, 0, 0, &rect);
    if (rc == 0){
        std::cerr << "can not paint map to ximage" << std::endl;
        delete []ximage.Point;
        std::exit(1);
    }
    const uchar* buf = reinterpret_cast<const uchar*>(ximage.Point);

    QImage img(buf, static_cast<int>(w),
                    static_cast<int>(h),
                    static_cast<int>(ximage.RowSize),
               QImage::Format_RGB16);
    if (!img.save(QString(filePath), "PNG")){
        std::cerr << "can not save image to file" << std::endl;
        delete []ximage.Point;
        std::exit(1);
    };
    delete []ximage.Point;
    return;
}

bool appendBorder(HOBJ borderObj, DFRAME* viewFrame){
    long rc =mapAppendPointPlane(borderObj,viewFrame->X1, viewFrame->Y1, 0);
    if (rc == 0){
     std::cerr << "can not append point to object Border" << std::endl;
     return false;
    }
    rc =mapAppendPointPlane(borderObj,viewFrame->X2, viewFrame->Y1, 0);
    if (rc == 0){
     std::cerr << "can not append point to object Border" << std::endl;
     return false;
    }
    rc =mapAppendPointPlane(borderObj,viewFrame->X2, viewFrame->Y2, 0);
    if (rc == 0){
     std::cerr << "can not append point to object Border" << std::endl;
     return false;
    }
    rc =mapAppendPointPlane(borderObj,viewFrame->X1, viewFrame->Y2, 0);
    if (rc == 0){
     std::cerr << "can not append point to object Border" << std::endl;
     return false;
    }
    rc =mapAppendPointPlane(borderObj,viewFrame->X1, viewFrame->Y1, 0);
    if (rc == 0){
     std::cerr << "can not append point to object Border" << std::endl;
     return false;
    }
    mapCommitObject(borderObj);
    return true;
}

bool updateBorder(HOBJ borderObj, DFRAME* viewFrame){
    long rc =mapUpdatePointPlane(borderObj,viewFrame->X1, viewFrame->Y1, 1, 0);
    if (rc == 0){
     std::cerr << "can not append point to object Border" << std::endl;
     return false;
    }
    rc =mapUpdatePointPlane(borderObj,viewFrame->X2, viewFrame->Y1, 2, 0);
    if (rc == 0){
     std::cerr << "can not append point to object Border" << std::endl;
     return false;
    }
    rc =mapUpdatePointPlane(borderObj,viewFrame->X2, viewFrame->Y2, 3, 0);
    if (rc == 0){
     std::cerr << "can not append point to object Border" << std::endl;
     return false;
    }
    rc =mapUpdatePointPlane(borderObj,viewFrame->X1, viewFrame->Y2, 4, 0);
    if (rc == 0){
     std::cerr << "can not append point to object Border" << std::endl;
     return false;
    }
    rc =mapUpdatePointPlane(borderObj,viewFrame->X1, viewFrame->Y1, 5, 0);
    if (rc == 0){
     std::cerr << "can not append point to object Border" << std::endl;
     return false;
    }
    mapCommitObject(borderObj);
    return true;
}


int main(){

    if (!gis::coord::GisCoord::init()){
        std::cout << "can not init giscoord" << std::endl;
        return 1;
    }
    HMAP hmap = panorama::mapOpenData(MAP_PATH);
    if (hmap == 0){
        std::cerr << "can not open map" << MAP_PATH;
        return 1;
    }
    HSITE site = panorama::mapCreateAndAppendTempSite(hmap, RSC_PATH);
     if (site == 0){
         std::cerr << "can not create temp sit" << std::endl;
         return 1;
     }

    HOBJ squadObj = mapCreateSiteObject(hmap, site);
    if (squadObj == 0){
     std::cerr << "can not create object on temp site" << std::endl;
     return 1;
    }
    long rc = mapRegisterObjectByKey(squadObj, SQUAD_OBJ_KEY);
    if (rc == 0){
     std::cerr << "can not register object by key" << std::endl;
     return 1;
    }
    DFRAME mapFrame;
    rc = panorama::mapGetTotalBorder(hmap, &mapFrame, panorama::PP_GEO);
    if (rc == 0){
     std::cerr << "can not get frame of map" << std::endl;
     return 1;
    }
    double centerB = (mapFrame.X1 + mapFrame.X2)/2.0;
    double centerL = (mapFrame.Y1 + mapFrame.Y2)/2.0;
    double centerL2 = centerL + 0.00001;
    double centerB2 = centerB + 0.00001;
    rc = mapAppendPointGeo(squadObj, centerB, centerL);
    if (rc == 0){
     std::cerr << "can not append point to object Point" << std::endl;
     return 1;
    }
    rc = mapAppendPointGeo(squadObj, centerB2, centerL2);
    if (rc == 0){
     std::cerr << "can not append point to object Point" << std::endl;
     return 1;
    }
    mapCommitObject(squadObj);
    DFRAME viewFrame;
    rc = panorama::mapObjectViewFrameEx(squadObj, &viewFrame, 1);
    if (rc == 0){
        std::cerr << "can get object view frame" << std::endl;
    }
    HOBJ borderObj = mapCreateSiteObject(hmap, site);
    if (borderObj == 0){
     std::cerr << "can not create object text on temp site" << std::endl;
     return 1;
    }
    rc = panorama::mapRegisterObjectByKey(borderObj, BORDER_OBJ_KEY);
    if (rc == 0){
     std::cerr << "can not register text object by key" << std::endl;
     return 1;
    }
    if (!appendBorder(borderObj, &viewFrame)){
        return 1;
    }
    drawToFile(hmap, "map.png", 900, 600);
    double scale = mapGetRealShowScale(hmap);
    panorama::mapSetSiteScale(hmap, site, static_cast<long>(scale));
    scale *= 2.0;
    scale = mapSetRealShowScale(hmap, scale);
    rc = panorama::mapObjectViewFrameEx(squadObj, &viewFrame, 1);
    if (rc == 0){
        std::cerr << "can get object view frame" << std::endl;
    }
    if (!updateBorder(borderObj, &viewFrame)){
        return 1;
    }
    drawToFile(hmap, "map_scaled_up.png", 900, 600);
    scale /= 4.0;
    scale = mapSetRealShowScale(hmap, scale);
    rc = panorama::mapObjectViewFrameEx(squadObj, &viewFrame, 1);
    if (rc == 0){
        std::cerr << "can get object view frame" << std::endl;
    }
    if (!updateBorder(borderObj, &viewFrame)){
        return 1;
    }

    drawToFile(hmap, "map_scaled_down.png", 1500, 600);
    mapFreeObject(borderObj);
    mapFreeObject(squadObj);
    mapCloseData(hmap);
    gis::coord::GisCoord::deinit();
    return 0;
}
При приближении карты знак векторного объекта уменьшается, а рамка отображения нет - она значительно больше знака объекта (из-за чего кстати я при работе с объектами делаю много лишней работы по перерисовке обновлённых участков карты).

Изображения:
map.png
map_scaled_down.png
map_scaled_up.png

Каким способом можно обновить рамку знака объекта или вычислить актуальную ?
Изменено: Владимир Егоров - 21.11.2018 17:59:10
 
Приветствую!

При помощи mapObjectViewFrameEx рамку, которую Вы хотите, получить не получится. Пример: создаем векторный знак (танк, например) с первой точкой в (0,0), второй где-нидь под Казанью.. mapObjectViewFrameEx вернет рамку примерно такого же размера как от экватора до Казани, хотя сам объект будет значительно меньше.
Кроме того что mapObjectViewFrameEx учитывает метрику, он еще и игнорирует признаки масштабируемости и сжимаемости объектов. (поэтому получается, что знак увеличиваться в размере при увеличении масштаба перестал, а рамка полученная при помощи mapObjectViewFrameEx  продолжает расти )
Тут неоднократно поднимались темы как определить реальные размеры знака на экране. Но работающего хотя бы на 90% процентов варианта, лично мне найти не удалось) Возможно, Вам повезет больше)

С уважением,
Матвеев П.В.
 
Цитата
Павел Матвеев написал:
(поэтому получается, что знак увеличиваться в размере при увеличении масштаба перестал, а рамка полученная при помощи mapObjectViewFrameEx  продолжает расти )
При уменьшении масштаба отображения  видимо Вы имели в виду ?

Рамка, полученная при помощи mapObjectViewFrameEx не увеличивается и не уменьшается - она не меняется. mapObjectViewFrameEx возвращает рамку в метрах в системе карты (плоские прямоугольные СК-42, например).
Визуальный эффект её увеличения связан с тем, что масштаб уменьшился (с 1:100000 до 1:50000, к примеру), и теперь рамка с размером 1494 x1494 метров (в СК-42) в пиксельных координатах занимает больше места.

Мне не нужны
Цитата
реальные размеры знака
Мне нужно чтобы функции с таким описанием
Код
 // Запрос/Пересчет габаритов изображения знака объекта (в метрах)
 // info   - идентификатор объекта карты в памяти
 // dframe - габариты изображения объекта в метрах
 // force  - признак принудительного пересчета габаритов (необходимо установить,
 //          если объект редактировался, но не записан на карту)
 // При ошибке возвращает ноль

_MAPIMP long int _MAPAPI mapObjectViewFrameEx(HOBJ info, DFRAME *dframe,
                                              long int force);
_MAPIMP long int _MAPAPI mapObjectViewFrame(HOBJ info, DFRAME *dframe);
действительно возвращали (пересчитывали) габариты изображения знака объекта (в метрах).

А так пока получается что я ни текстовую подпись вообще никаким способом к объекту не смогу приделать,
ни отрисовку объектов эффективно реализовать не смогу. Меня сейчас отрисовка даже больше волнует. Ведь на маленьких масштабах все мои потуги по обработке перемещений (редактирования) объектов вообще никакого смысла не имеют, вместо того чтобы перерисовать два небольших участка карты я получается перерисовываю почти всю карту (ту её часть, что отображается в нашем в приложении в текущий момент).
 
Приветствую!

с 1:100000 до 1:50000 знаменатель масштаба уменьшился, а масштаб увеличился.

Используя mapObjectViewFrameEx "приделать" подпись к знаку в общем случае у меня не получилось. Даже если бы рамка и соответствовала размерам знака на экране, то Вам пришлось бы перемещать подписи при каждом изменении масштаба.



Матвеев П.В.
 
Цитата
с 1:100000 до 1:50000 знаменатель масштаба уменьшился, а масштаб увеличился.
Ок, понял =)

Цитата
Даже если бы рамка и соответствовала размерам знака на экране, то Вам пришлось бы перемещать подписи при каждом изменении масштаба.
Я именно этим и занимаюсь. У меня подписи входят в набор объектов, где родительский (GROUPLEADER) объект - это объект к которому относится подпись, а сама подпись - подчинённая (GROUPSLAVE). И при изменении масштаба я для всех групп объектов, у которых дочерние объекты привязаны к рамке объекта ( а не к точке из метрики) собирался в дочерних объектах редактировать метрику. Но посмотрев на то что рамка постоянная, написал сюда.


А каким-либо другим образом приделать подпись у Вас получилось? Поделитесь ?
 
Или вот ещё.

Функция mapGetObjectContour - что она вообще считает ?

Код
 // Определяет габариты объектов (точечных, векторных и подписей) с учетом текущих  // 17/11/17
 // условий отображения (см. функции mapGetRealShowScale/mapSetRealShowScale и
 // mapGetScaleMethod/mapSetScaleMethod)
 // Для каждого подобъекта подписи создается прямоугольный подобъект,
 // ограничивающий текст подписи
 // info    - исходный объект
 // contour - объект, в который заносятся габариты исходного объекта
 // hPaint  - идентификатор контекста отображения для многопоточного вызова функции 
 //           отображения (может быть ноль)
 // При ошибке возвращает 0

_MAPIMP long int _MAPAPI mapGetObjectContour(HOBJ info, HOBJ contour, HPAINT hPaint);

В том же примере вызвал эту функцию для объекта squad, потом распечатал метрику из объекта contour (куда должны были записаться габариты объектов):
Код
    rc = panorama::mapGetObjectContour(squadObj, contourObj,0);
    if (rc == 0){
        std::cerr << "can not get contour of squad" << std::endl;
    }else{
        long pc = mapPointCount(contourObj, 0);
        std::cout << "point count of contour:" << pc << std::endl;
        for (long i = 0; i< pc; i++){
            DOUBLEPOINT p;
            mapGetPlanePoint(contourObj, &p, i+1, 0);
            std::cout << "point[" << i+1 << "]= X:" << p.X << " Y:" << p.Y << std::endl;
        }
        mapCommitObject(contourObj);

    }

Вывод:
point count of contour:5
point[1]= X:3.68714e+07 Y:4.44749e+07
point[2]= X:3.68709e+07 Y:4.44758e+07
point[3]= X:3.68743e+07 Y:4.44778e+07
point[4]= X:3.68748e+07 Y:4.44769e+07
point[5]= X:3.68714e+07 Y:4.44749e+07

А mapObjectViewFrameEx вернул мне следующее (скопировал из дебаггера):
Код
      viewFrame   @0x7fffffffe320   DFRAME
         X1   6152256.5999999996   double
         X2   6155156.5999999996   double
         Y1   7419153.5   double
         Y2   7422053.5   double
 
Приветствую!

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

ЗЫ: mapGetObjectContour надо посмотреть, вдруг это то, что надо..)
С уважением,
Матвеев П.В.
 
Интересен официальный ответ от разработчиков.

Может я слишком многого ожидаю от mapObjectViewFrameEx.
 
Приветствую!

Пока мы ждем официального ответа от разработчиков посмотрел на mapGetObjectContour
В общем, при помощи этого метода действительно можно получить рамку вокруг объекта. Она учитывает поворот знаков и практически является описанным прямоугольником. Но...

1. Для ряда знаков она учитывает поворот в случаях когда это не надо, например, для ПУ из operator.rsc флаги поворачиваются только вправо-влево, а рамка рассчитывается как для обычного векторного знака, который поворачивается на произвольный угол.
2. Не учитывает признаки сжимаемости\растяжимости (проверял на пользовательских подписях)
3. Правильно работает только на масштабах близких к базовому масштабу. при увеличении масштаба больше чем базовый в 4 и более раз начинает возвращать неправильные значения (похоже на какое-то переполнение)

В общем как-то так)

С уважением,
Матвеев П.В.
 
Цитата
В общем, при помощи этого метода действительно можно получить рамку вокруг объекта. Она учитывает поворот знаков и практически является описанным прямоугольником.
У меня в версии 12.3.1 выдало что-то совсем не вразумительное
Цитата
Владимир Егоров написал:
В том же примере вызвал эту функцию для объекта squad, потом распечатал метрику из объекта contour  (куда должны были записаться габариты объектов):
rc = panorama::mapGetObjectContour(squadObj, contourObj,0);
   if (rc == 0){
       std::cerr << "can not get contour of squad" << std::endl;
   }else{
       long pc = mapPointCount(contourObj, 0);
       std::cout << "point count of contour:" << pc << std::endl;
       for (long i = 0; i< pc; i++){
           DOUBLEPOINT p;
           mapGetPlanePoint(contourObj, &p, i+1, 0);
           std::cout << "point[" << i+1 << "]= X:" << p.X << " Y:" << p.Y << std::endl;
       }
       mapCommitObject(contourObj);

   }

Вывод:
point count of contour:5
point[1]= X:3.68714e+07 Y:4.44749e+07
point[2]= X:3.68709e+07 Y:4.44758e+07
point[3]= X:3.68743e+07 Y:4.44778e+07
point[4]= X:3.68748e+07 Y:4.44769e+07
point[5]= X:3.68714e+07 Y:4.44749e+07
Страницы: 1 2 След.
Читают тему (гостей: 1)



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

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