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

снимок карты в нужном масштабе

Поиск  Пользователи  Правила  Войти
Форум » Настольные приложения » GIS ToolKit, GIS ToolKit Active, ГИС Конструктор для Windows
Страницы: 1 2 След.
RSS
снимок карты в нужном масштабе
 
Здравствуйте

подскажите пожалуйста, как решить проблему:
требуется создать снимок карты, в указанной рамке (в метрах), в максимальном масштабе.
размеры конечной картинки задаются в пикселях.
требуется найти максимальный масштаб карты для создания снимка вызовом SaveFrameToEmfEx.
в принципе, это пропорция размера прямоугольника карты в метрах к размеру картинки нужного размера.
есть ли функция mapapi, которая которая переводит ширину и высоту (не точка X/Y!) из пикселей в метры и обратно?
есть ли уже готовая функция вычисления масштаба под указанный размер отображения в winapi для подобной цели?
Изменено: mihalych72 - 08.11.2022 16:49:25
 
Здравствуйте Елена.
Спасибо за помощь.

у меня gtk последний free.
в организации официальная панорама. версия не новая. кажется 12я. ключ у главного программиста.

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

подскажите формулы для вычисления масштаба. не могу сообразить, как соотнести экранный размер к метрам.
тем более нужна еще поправка на соотношение ширины к высоте.
 
Цитата
mihalych72 написал:
в принципе, это пропорция размера прямоугольника карты в метрах к размеру картинки нужного размера.
на этот коэффициент нужно изменить текущий масштаб, только метры в пиксели надо перевести через mapPlaneToPicture
 
Цитата
mihalych72 написал:
у меня gtk последний free.

Можно воспользоваться методом TMapView.ConvertMetric, либо - как подсказали выше использовать MAPAPI - mapPlaneToPicture
А для прямоугольной рамки есть TMapView.ConvertDFrame.

Что касается функции SaveFrameToEmfEx, то она выводит в векторный формат EMF фрагмент карты заданный рамкой в метрах на местности. То есть будет выведен один и тот же фрагмент всегда, не зависимо от масштаба отображения.
Масштаб влияет только на состав отображаемых данных в соответствии с масштабными рядами отображения объектов - как задано в классификаторе.

Рекомендую пользоваться поиском по сайту: тут я выкладывал небольшой пример приложения на Delphi + GTK для выгрузки в EMF.
 
Цитата
Денис Вицко написал:
Что касается функции  SaveFrameToEmfEx , то она выводит в векторный формат EMF фрагмент карты заданный рамкой в метрах на местности. То есть будет выведен один и тот же фрагмент всегда, не зависимо от масштаба отображения.

Здравствуйте, Денис
Вы меня не поняли.
рамка нужна чтобы выбрать объекты на карте. сейчас рамка фиксирована: 200х200 метров. при создании отчета выполняется переход на масштаб 1:1000, делается снимок карты, используя SaveFrameToEmfEx, в формате SCREEN !
все работает. картинка влазит на лист А3 альбом. размер картинки подогнали под размер рамки 200х200м


поменялось условие:
не влазят нужные объекты в размер 200х200м. теперь хотят менять размер рамки.
но при этом, при фиксированном масштабе 1:1000 меняется размер конечной картинки и она вылезает за лист А3.

либо я где-то накосячил и у меня формируется картинка с другими размерами, либо вопрос: как мне самому вычислить нужный масштаб карты под размер рамки, чтобы, через SaveFrameToEmfEx, формировалась картинка строго заданного размера?
я еще перепроверю свой код. может действительно это мои ошибки.
 
Цитата
Дмитрий Паньков написал:
на этот коэффициент нужно изменить текущий масштаб, только метры в пиксели надо перевести через mapPlaneToPicture
Спасибо Дмитрий, функцию посмотрю.


но Вы меня наверно не так поняли.
когда я выделяю объекты рамкой, я могу работать с картой в любом масштабе.
сейчас рамка фиксирована 200х200 метров. ее размер соответствует для отчета на А3 при снимке карты в масштабе 1:1000
т.е. когда формирую отчет, масштабирую карту в 1:1000, и картинку вставляю в отчет. все норм.

сейчас размеры рамки меняются.
когда перехожу на масштаб 1:1000, у меня создается картинка с другими размерами. формат картинки SCREEN. искажение происходит, когда я этот растр начинаю переводить под нужные размеры картинка искажается.
потому мне нужно самому вычислить максимальный масштаб карты под фиксированный размер картинки.
перейти в этот масштаб и сделать снимок - проблем нет.
проблема - вычислить наименьший масштаб для снимка под нужный размер картинки с учетом размера рамки.
я не математик и для меня это сложно. я в пропорциях запутался.
точность не нужна, допускается чтобы картинка была меньше, но не больше, иначе она пересекает лист и накладывается на текст в отчете.
 
Получается, речь не про то, как выгрузить изображение карты, а про то, как это изображение вставить в лист A4, сохранив пропорции.
Масштаб карты тут не при чем, как и габариты рамки, по которой формируется картинка.
Рамкой выбираете интересующую местность на карте, получаете картинку.

Надо понять следующее.
Пиксели экрана - это не пиксели печатного листа.

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

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

Посмотрите реализацию методов компонента TMapView:
Цитата

// Отобразить всю карту в окне
   procedure    ShowAllMapInWindow;
// Отобразить карту по ширине окна
   procedure    ShowAllMapInWindowByWidth;
// Отобразить карту по высоте окна
   procedure    ShowAllMapInWindowByHeight;
// Установить масштаб для отображения заданного фрагмента в окне
   procedure    ScaleByFrame(const frame: TDFRAME; place: TPPLACE);
   procedure    ScaleByFrame(const leftbottom, righttop : TDOUBLEPOINT; place: TPPLACE);
 
Денис Вицко написал:
Цитата
Получается, речь не про то, как выгрузить изображение карты, а про то, как это изображение вставить в лист A4, сохранив пропорции.Масштаб карты тут не при чем, как и габариты рамки, по которой формируется картинка.Рамкой выбираете интересующую местность на карте, получаете картинку.
Спасибо, Денис
посмотрю указанные Вами методы.

рамка - это действительно, выбор объектов на карте. рамка задается в метрах.
картинка должна вписаться в лист отчета.
если я буду масштабировать уже готовую картинку - она искажается.
в SaveFrameToEmfEx я указываю делать снимок качеством cVT_SCREEN, и в emf лежит объект bitblt (bitmap), а не векторная карта.

в отчете картинка печатается без autosize. подгонка к размерам листа отключена. т.е. картинка печатается как есть в emf.

факты

имеется рамка с известным размером = 200х200 в метрах (координаты углов в метрах)
ожидается картинка с размером = 1060х1020 в пикселях

задача:сделать снимок карты по заданной рамке в минимальном масштабе (максимальное увеличение).
найти такой масштаб карты, при котором будет создана картинка с заданными размерами чтобы отобразилась карта в пределах рамки.

сейчас рамка фиксирована и равна 200х200м
при масштабе карты 1:1000 получается картинка размером 1060х1020 пикселей
снимок карты получается строго по рамке.все замечательно.


когда размеры рамки не 200х200, я перехожу на карту в масштаб 1:1000 и у меня карта отображается не по рамке.
мне нужно найти такой масштаб карты, при котором карта отобразится в пределах рамки (по максимому), а потом сделать снимок карты. и конечная картинка должна быть размером 1060х1020.

я пока не понял почему размер картинки формируется как 1060х1020. я ведь не указываю размеры картинки при вызове SaveFrameToEmfEx
получается что это размер окна просмотра карты в MapView? но я когда создаю фоновый MapView не задаю ему свойство Align=alClient  размеры clientrect тоже не указываю.

 // создаем новый объект просмотра карты
 if fUseNewMapView
   then fMapView:= TMapView.Create( NIL)
   else fMapView:= aMapViewMain;

 try
   if fUseNewMapView then begin
     DoLog( 'Используется новый объек MapView.');
     // кладем его на подложку главного экрана
     fMapView.Parent := aMapViewMain.Parent;
     // скрываем объект
     fMapView.Visible := FALSE;
     // перенаправляем MapView либо на локальную карту, либо на сервер
     if ASSIGNED( fMapGisServerNew) then begin
       DoLog( 'Используется подключение к гис-серверу через fMapGisServerNew.');
       fMapGisServerNew.MapView := fMapView;
       // открываем карту, указанную при подключении к гис-серверу
       fMapView.MapOpen( fMapGisServerMapAlias, TRUE);
     end else begin
       if ASSIGNED( fMapGisServer) then begin
         DoLog( 'Используется подключение к гис-серверу через fMapGisServer.');
         // перенаправляем тек.объект работы с картой
         // на указанный гис-сервер
         fMapGisServer.MapView := fMapView;
         // открываем карту, указанную при подключении к гис-серверу
         fMapView.MapOpen( fMapGisServerMapAlias, TRUE);
       end else begin
         DoLog( 'Используется локальная карта: "%s".', [ aMapViewMain.MapFileName]);
         // открываем такуюже карту
         fMapView.MapFileName := aMapViewMain.MapFileName;
       end;
     end;
     // подключаемся к карте
     // открываем карту в новом контроле
     fMapView.MapView := true;
     fMapView.ViewType := aMapViewMain.ViewType;//cVT_SCREEN;//cVT_PRINTRST;
     fMapView.Repaint;
   end;
   
   // выставляем указанный масштаб карты
   fMapView.ViewScale := aMapScale;             //=1000 - указывается при вызов этого кода

   // формируем снимок карты
   // создаем новый объект рамки в новом контроле отображения карты
   fMapFrameRect:= TGTK_MapFrameRect.Create( fMapView);
   try
     // импортируем описание рамки и создаем объект рамки на временном
     // контроле просмотра карты
     fMapFrameRect.SetMRect( aMFrameRect);
     // делаем снимок карты в рамке
     Result := fMapFrameRect.CaptureImage( SELF.FileNameEMF, aMapBorder);


fMapFrameRect.CaptureImage:

function TGTK_MapFrameRect.CaptureImage( const aFileNameEMF: string;
                            aBorder: boolean = FALSE): Boolean;
Var
 parm: TMETAFILEBUILDPARMEX;
 NameEmf: string;
begin
 { здесь сохраняется картинка под текущей рамкой }

 Result := FALSE;
 
 if ( LENGTH( aFileNameEMF) <= 0)
   then Exit;

 if NOT Active
   then Exit;
   
 FillChar( parm, SizeOf(TMETAFILEBUILDPARMEX), 0);
 parm.Frame := MRect;          // <--- это вызов  fMapFrameRect.SetMRect( aMFrameRect); , т.е. здесь указываются координаты рамки aMFrameRectи все!
 parm.Scale := MapView.ViewScale;
 parm.VisualType:= cVT_SCREEN;
  // VisualType:= cVT_PRINT;
 if aBorder
   then parm.Border := 1
   else parm.Border := 0;
 parm.DontClip  := 0;
 parm.Black     := 0;
//  parm.Intensity := 70;

 // Сохранение в файл Emf
 Result := ( MapView.SaveFrameToEmfEx( aFileNameEMF, parm) <> 0);
end;

я не делаю вызовов, которые Вы посоветовали - подстроить масштаб карты под clientrect просмотра карты.
откуда размер картинки 1060х1020?



я пока чего-то не понимаю.
просьба вывести меня из этого состояния.
Изменено: mihalych72 - 09.11.2022 19:21:46
 
Цитата
mihalych72 написал:
я пока чего-то не понимаю.просьба вывести меня из этого состояния.

Дело в том, что круглую Землю отобразить на плоскости, и в частности - на экране, - нетривиальная задача.
А если еще учесть, что Земля совсем не круглая, то еще сложнее.

Для этого существует море различных проекций.

Картографические проекции и методика их выбора для создания карт различных типов. Руководство картографа

Метры на местности будут кратны квадратным пикселям на экране только в очень исключительных случаях.

Поэтому Ваша картинка 1060х1020, соответствующая Вашему фрагменту местности 200х200м - это частный случай.
Сдвиньте эту рамку ближе к полюсу или ближе к экватору - и получите совершенно другой результат.
 
Обычно расчет отображаемой области идет от центра картинки.
Есть координаты в метрах или в геодезической системе координат центра отображаемого фрагмента (важного объекта).

Устанавливается заданный масштаб и заданное разрешение изображения.
Код
  // Установить масштаб отображения (знаменатель масштаба)
  // hmap - идентификатор открытых данных
  // x, y - координаты предполагаемого "центра изображения"
  //        (любой точки привязки) в окне в текущем масштабе или нули
  // scale - реальный масштаб отображения, который желают получить
  // hpaint - идентификатор контекста отображения для многопоточного вызова
  // Возвращает: 0 - масштаб не изменился, 1 - масштаб изменился
  // x, y - координаты предполагаемого "центра изображения"
  //        в окне относительно всей картинки в новом масштабе отображения
  // При ошибке возвращает ноль

_MAPIMP long int _MAPAPI mapSetRealScalePro(HMAP hmap, long int *x, long int *y, double scale, HPAINT hPaint);
Выполняется пересчет центра в условные пиксели.
Код
// Преобразование из метров на местности в пикселы на
 // изображении
 // hmap - идентификатор открытых данных
 // x,y  - преобразуемые координаты

_MAPIMP void _MAPAPI mapPlaneToPicturePro(double *x, double *y, HPAINT hPaint);
От центра вычитается/прибавляется половина ширины/высоты картинки - получаем ожидаемую рамку в точках.

Чтобы не "портить" состояние основного документа операции по смене масштаба и разрешения делают на отдельном контексте отображения -
Код
// Создать/Удалить контекст отображения для многопоточного вызова
 // функций mapPaintByFramePro или mapPaintByFrameToXImagePro
 // hmap - идентификатор открытых данных
 // hpaint - контекст отображения для копирования параметров отображения\печати или 0
 // Для каждого потока создается свой контекст и передается в качестве параметра функции
 // В каждом контексте создается свой буфер отображения и выделяется память под служебные области
 // Размер резервируемой памяти помимо буфера отображения может занимать 1-2 Мбайта,
 // внутренний буфер отображения для размера 1920x1080 занимает 8 Мбайт
 // Размер может устанавливаться программно - mapSetMaxScreenImageSize
 // При ошибке возвращает ноль

_MAPIMP HPAINT _MAPAPI mapCreatePaintControlEx(HMAP hmap, HPAINT hpaint);
_MAPIMP void _MAPAPI mapFreePaintControl(HPAINT hpaint);

Это теория.
При сохранении в EMF векторного изображения контекст вывода (внутренний HDC) создается на основе
умалчиваемого драйвера принтера и разрешение будет соответствовать ему (например, 600 dpi). Но эта картинка масштабируемая (векторный EMF)
и в дальнейшем впишется в другой размер фрагмента при отображении.

При выводе VT_SCREEN разрешение будет экранным - 96 dpi,  а изображение в виде растра (BMP). Применение HPAINT hPaint не требуется.
Можно просто сменить масштаб и пересчитать метры в пикселы для оценки размеров области.
Или, если важно сохранить размер области в метрах, то сделать отступ в метрах и угловые точки пересчитать в пикселы.
Страницы: 1 2 След.
Читают тему (гостей: 1)



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

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