View Issue Details

IDProjectCategoryView StatusLast Update
0002763SAS.ПланетаХотелка / Feature requestpublic03-08-2015 08:43
ReporterGunSmoker Assigned ToGunSmoker  
PrioritynormalSeverityminorReproducibilityN/A
Status resolvedResolutionfixed 
PlatformWindowsOS8.1OS Versionx64
Product Version141212 
Target Version150915Fixed in Version150915 
Summary0002763: Добавить возможность наложения слоёв при экспорте/копировании
DescriptionХочется выгрузить карту в PNG тайлы и подсунуть её программе. Нужен спутник (Google) с наложением поверх его гибрида.

В настоящее время возможность наложения есть только для экспорта в sqlite/RMaps ( 0001823 ).

Я посмотрел результат склейки RMaps - там в БД лежат готовые тайлы с уже наложенным поверх слоем. Т.е. код наложения уже есть и работает. Собственно, непонятно, что мешает сделать эту же возможность для всех прочих операций копирования/экспорта.
Additional InformationКогда-то такая задача решалась утилитой SASMerge, которая сегодня мертва и больше не доступна.
TagsSQLite, склейка, экспорт

Relationships

related to 0000325 resolvedGunSmoker При копировании кэша менять тип файлов (jpg->png) 
related to 0001680 confirmed экспорт в тайловый кэш с заменой проекции 
related to 0002779 assignedGunSmoker Перенести копирование тайлов с изменением со влкадки Скопировать на вкладку Экспорт 

Activities

zed

10-07-2015 20:59

manager   ~0016120

>непонятно, что мешает сделать
Ничего не мешает. Как говорится - бери да делай :)

GunSmoker

12-07-2015 04:36

developer   ~0016142

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

zed

12-07-2015 06:40

manager   ~0016143

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

По поводу "наворочу": глядя на пример того же RMaps, я думаю, будет трудно наворотить. Для комбинирования слоёв с картой используется TBitmapLayerProviderMapWithLayer, который инициализируется картой и слоем (или списком слоёв), а потом у него последовательно запрашиваются тайлы в нужной проекции. Далее, результат конвертируется в нужный формат при помощи IBitmapTileSaver (который возвращает фабрика TBitmapTileSaveLoadFactory) и сохраняется в хранилище или ещё куда угодно. Главное понимать в какой проекции получился ваш тайл и какую проекцию ожидает/поддерживает хранилище или целевой формат, если речь о экспорте.
 
Проекцию вы може взять либо у исходного хранилища из которого читаете тайлы:
VGeoConvert := FTileStorage.CoordConverter;
VProjection := FProjectionFactory.GetByConverterAndZoom(VGeoConvert, FZoom);
Либо создать одну из 3-х доступных:
VGeoConvert := FCoordConverterFactory.GetCoordConverterByCode(
        CGoogleProjectionEPSG,
        CTileSplitQuadrate256x256
      );
VProjection := FProjectionFactory.GetByConverterAndZoom(VGeoConvert, FZoom);
И в итоге, с координатами вам вообще не нужно иметь дела, да и тайлохранилища спрятаны за интерфейсами, так что вы даже не почувствуете разницы при записи в разные типы.

Если что-то не понятно, спрашивайте.

zed

12-07-2015 06:48

manager   ~0016144

Хороший пример создания IBitmapTileUniProvider можно подсмотреть в склейке, в функции TfrMapCombine.GetProvider - там на выбор можно либо наложить все отображаемые слои, либо один конкретный, ну или вообще не накладывать. Правда, в экспорте нужно учитывать, что если мы ничего не накладываем поверх карты и нас устраивает проекция и формат изображений тайлохранилища, то тайлы нужно передавать напрямую из хранилища, без лишней конвертации в битмапку. Т.е. этим провайдером не пользоваться.

vdemidov

12-07-2015 10:14

manager   ~0016145

Вообще то, я давно планирую перевести экспорты оперирующие тайлами (JNX, сохранение в тайлохранилище и тд) на использование интерфейса ITileInfoUniProvider, у которого экспорт может запросить требуемый тайл с инофрмацией о типе и времени создания. А уже реализация этого провайдера может или напрямую передавать инфу из тайлохранилища, или склеивать и пределывать тайлы налету, или даже просто рендерить тайлы слоя заполнения или меток. Просто все руки никак не доходят сделать.

GunSmoker

12-07-2015 16:10

developer   ~0016146

Last edited: 12-07-2015 16:29

zed, может тогда подскажешь (запишу вопросы в том числе и себе, для упорядочивания в голове):
- Пока вижу так: в TThreadCopyFromStorageToStorage.ProcessTile загрузить тайл в bitmap, слить его с наложением, подсунуть в SaveTile.
- Тайлы всегда одинаковые по размеру (256x256)?
- ITileStorage.SaveTile.AData - передаётся, как я понимаю, содержимое файла. Как узнать, в каком формате нужно передавать (jpg/png)? IContentTypeInfoBasic? По строкам анализировать что-ли? Или по BOM из AData? Как узнать качество сжатия и цветность? Или выносить это как настройку в UI?
- ITileStorage.GetTileInfoEx - аналогичный вопрос: в каком формате возвращает.
- В TThreadCopyFromStorageToStorage.ProcessTile не вижу преобразования форматов (jpg->png;png->jpg). Кто это выполняет?
- Пока нет понимания, что делать с проекциями, как выполнять преобразования, если они нужны.
- В коде для экспорта в RMaps вижу упоминания CGoogleProjectionEPSG. Чем она специальна?
- Количество поясняющих комментариев угнетает :)

GunSmoker

12-07-2015 16:14

developer   ~0016147

Кстати, с FastMM в FullDebugMode при закрытии вываливаются утечки, иногда - ошибки. Это так и должно быть? :)

zed

12-07-2015 17:08

manager   ~0016148

>в TThreadCopyFromStorageToStorage.ProcessTile загрузить тайл в bitmap
Копирование из хранилища в хранилище происходит на самом низком уровне и там нету никаких преобразований. Тупо перекидывается бинарь из одного в другое. Чтобы оперировать битмапами и проекциями, нужно подняться на уровень выше, до IMapType - это уже карта, у неё можно запрашивать битмапы в любой известной проекции. А брать из хранилища тайлы и самому пытаться их распаковать в битмап, не стоит. И TBitmapLayerProviderMapWithLayer оперирует как раз картами, его и нужно использовать.

>Тайлы всегда одинаковые по размеру
Пока что да.

>Как узнать, в каком формате нужно передавать (jpg/png)?
Можно взять Saver у карты, а можно спросить и пользователя. См. как это сделано в TfrExportRMapsSQLite.GetBitmapTileSaver, там как раз все варианты присутствуют.

>ITileStorage.GetTileInfoEx - аналогичный вопрос: в каком формате возвращает
Можно узнать какой из интерфейсов поддерживается: IContentTypeInfoBitmap или IContentTypeInfoVectorData и получить Saver/Loader. Далее, можно сравнить свой Saver с полученным. Так можно проверить формат, но не настройки сохранения, они могут отличаться.

>вижу упоминания CGoogleProjectionEPSG. Чем она специальна?
Ничем. Просто RMaps других не понимает, если правильно помню, вот и происходит принудительная конвертация при необходимости.

>при закрытии вываливаются утечки, иногда - ошибки
Возможно это 0002050

zed

12-07-2015 17:23

manager   ~0016149

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

GunSmoker

12-07-2015 18:00

developer   ~0016150

Да-да, уже делаю две вкладки, одна - прямое копирование (как есть), вторая - с преобразованием (моё).

zed

12-07-2015 18:39

manager   ~0016151

А смысл прямого копирования?

GunSmoker

12-07-2015 19:32

developer   ~0016152

В смысле? Под "как есть" я имел в виду то, что сейчас делает вкладка "Скопировать". Там же прямое копирование тогда получается, или нет?

GunSmoker

12-07-2015 19:52

developer   ~0016153

> Возможно это 0002050

Похоже некоторые потоки не закрываются при выходе из программы. Или не успевают завершиться. Возможно не отпускается ссылка на поток?

GunSmoker

13-07-2015 00:19

developer   ~0016154

> Копирование из хранилища в хранилище происходит на самом низком уровне и там нету никаких преобразований. Тупо перекидывается бинарь из одного в другое.

1. Если источник - png, а сохраняется в jpg? Что тогда? Или получается, что формат хранилища не диктует формат файла?
2. Если не совпадают проекции источника/цели? Надо же конвертацию какую-то выполнить?

GunSmoker

13-07-2015 01:34

developer   ~0016155

Кажется, что-то получилось.

Сделал новую вкладку, сделал отдельный модуль с новым потоком, на вход - BitmapLayerProviderMapWithLayer, как в RMaps, и TileStorage, как в Copy. Копирует с наложением в выбранный формат хранилища - ОК. Результат такого "модифицирующего" копирования вроде совпадает с "прямым копированием" - по файловой структуре и координатам в тайлах (за исключением самого содержимого рисунков, конечно - но если убрать слой наложения, то совпадает и контент рисунков).

Но, похоже, с преобразованием координат между слоями что-то не то (??). Если копировать гугл+гугл = ОК, если гугл+яндекс = ОК, а если яндекс+гугл = срабатывает Assert в TBitmap32StaticFactory.BuildWithOwnBuffer (FBackEndByStatic.FBitmapStatic = nil). Вроде как цикл в TMapType.LoadBitmap не выполняется ни разу. Сложно отлаживать, т.к. почему-то в этом коде 2007-я виснет постоянно (вместе с ОС).

zed

13-07-2015 02:05

manager   ~0016156

>Под "как есть" я имел в виду
Ну вот мне и не понятно зачем делать тоже самое, что уже есть на другой вкладке. Разве что чисто потренироваться?

>Если источник - png, а сохраняется в jpg?
Как оно вдруг станет jpeg, если там нету конвертирования?

>Если не совпадают проекции источника/цели?
Источник и цель это кэш одной и той же карты, поэтому проекция там всегда одна. А вот если попытаться скопировать в кэш другой карты, то это уже на свой страх и риск, и нужно понимать что делаешь. Перепроецирования нету.

>а если яндекс+гугл = срабатывает Assert
Не видя кода, сложно сказать. Но "гугл+яндекс" это тоже разные проекции.

>2007-я виснет постоянно (вместе с ОС)
Я обычно использую XE2 при разработке, попробуй её. А D2007 только если приходится на старом железе в XP работать, ну и для проверки, что ночнушка соберётся.

GunSmoker

18-07-2015 09:43

developer   ~0016172

Я XE в основном использую. Под ней на хостовой машине всё отладил - нашёл у себя в коде ошибку. Теперь вроде всё работает. Пока, правда, особо не тестировал.

Теперь вопрос - эти изменения как и куда заливать?

zed

18-07-2015 10:00

manager   ~0016173

Порядок принятия изменений в код

GunSmoker

19-07-2015 04:10

developer   ~0016174

zed, а не подскажешь, вот в 0000780 просили кэш вида <ZOOM>\<Y>\<X>.png. Мне как раз он нужен для экспорта. Вроде как он реализован в u_TileFileNameGM3.pas и обзывается rsGlobalMapperBingCacheName = 'GlobalMapper Bing'. Вопрос: почему он не создаётся в u_TileStorageTypeListSimple.pas?

zed

19-07-2015 07:58

manager   ~0016175

Похоже, что про него просто забыли. Нужно добавлять.

zed

19-07-2015 09:22

manager   ~0016176

Пофиксил: https://bitbucket.org/sas_team/sas.planet.src/commits/d271b7d95284db9041580a9865c3569a57eab0d3

GunSmoker

19-07-2015 15:06

developer   ~0016177

Гы, я его тоже восстановил и думал заливать это или нет :)


Я ещё поиграюсь немного.

GunSmoker

21-07-2015 04:37

developer   ~0016191

По основным исходникам - создал пул-реквест.

Но не могу сообразить, как правильно сделать внесение изменений в либы (requires)? Мне бы дефайны поправить для поддержки Delphi XE. Делаю форк и клон, вношу изменения, делаю коммит - а там же подхранилища, клиент хочет вносить изменения напрямую в ваши, а не в мой форк.

zed

21-07-2015 05:22

manager   ~0016192

>По основным исходникам - создал пул-реквест.
Тогда ждём резолюции от vdemidov-а.
Ты, кстати, зачем свой форк приватным сделал? Этот реквест вживую теперь фиг проверишь перед принятием.

>как правильно сделать внесение изменений в либы (requires)
Делаешь клон конкретной либы, делаешь туда пул-реквест, а как их принять в корневой репо (requires) уже наша задача.

В какую либу надо вносить изменения?

GunSmoker

21-07-2015 05:36

developer   ~0016193

> Ты, кстати, зачем свой форк приватным сделал? Этот реквест вживую теперь фиг проверишь перед принятием.

Я ж не знал :)

Поправил.

> Делаешь клон конкретной либы, делаешь туда пул-реквест, а как их принять в корневой репо (requires) уже наша задача.

Понял. У меня была проблема с поиском. Сейчас сделаю.

vdemidov

21-07-2015 07:30

manager   ~0016199

Смотрю реквест. Ощущения двойственные. За первых три коммита вообще очень благодарен. Особенно за "Добавлены проверки на наличие указания выходного файла/папки перед началом работ по региону"
А вот к остальным есть претензии.
Во-первых, мне не нравится добавление работы с расширением в ITileFileNameGenerator, так как я его от туда старательно убирал (по факту этот интерфейс нужно было переименовать в ITileNameGenerator). А логика по добавлению '.tile' к именам файлов должна жить внутри соответствующего типа тайлохранилища (отдельный класс или дополнительный параметр в конструктор TTileStorageFileSystem)
Во-вторых, лучше было закладку копирования вообще не трогать, а добавить экспорт в тайлохранилище и там уже выбирать тип тайлохранилища в том числе и добавленный отдельно 'OsmAnd+ Tiles'
Ну и в-третьих, хорошо бы причесывать коммиты перед созданием пул реквеста, что бы по возможности не было некомпилируемых по-отдельности коммитов как получились два предпоследних.

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

GunSmoker

21-07-2015 08:16

developer   ~0016201

Могу переделать вот это, но, наверное, будет это не ранее след. выходных:

"Во-первых, мне не нравится добавление работы с расширением в ITileFileNameGenerator, так как я его от туда старательно убирал (по факту этот интерфейс нужно было переименовать в ITileNameGenerator). А логика по добавлению '.tile' к именам файлов должна жить внутри соответствующего типа тайлохранилища (отдельный класс или дополнительный параметр в конструктор TTileStorageFileSystem)"

vdemidov

21-07-2015 08:22

manager   ~0016202

Тогда принимаю как есть, а там разберемся.

zed

21-07-2015 11:32

manager   ~0016206

Обращаю внимание на:
1. [DCC Warning] u_TileFileNameOsmAnd.pas(101): H2443 Inline function 'SameFileName' has not been expanded because unit 'Windows' is not specified in USES list
2. В dpr файле не отсортированы имена юнитов (нужно запустить Tools\UnitsSort.py см. 0002693)
3. В гуе на вкладке скопировать не вмещаются контролы, окно нужно растянуть по вертикали, чтобы по-умолчанию всё было видно.

zed

21-07-2015 11:37

manager   ~0016207

И вопрос по поводу пул-реквеста в alcinoe - там точно эти фиксы необходимы?

GunSmoker

23-07-2015 07:01

developer   ~0016219

Замечания поправлю.

> там точно эти фиксы необходимы?

Да, конечно. В XE же нет namespace-в для стандартных модулей. Они появились только в XE2. Так что для XE2 - "System.AnsiStrings.ЧТОТО", для XE - "AnsiStrings.ЧТОТО".

GunSmoker

24-07-2015 09:54

developer   ~0016220

Можно вопрос: зачем пишется код вида:

destructor TSomething.Destroy;
var
  I: integer;
begin
  for I := 0 to Length(FItems) - 1 do begin
    FItems[I] := nil;
  end;
  FItems := nil;
  inherited;
end;

Где FItems - динамический массив из интерфейсов.

Это для упрощения отладки? Или остатки от старого не-интерфейсного кода?

vdemidov

24-07-2015 10:29

manager   ~0016221

Скорее всего остатки старого неинтерфейсного кода, или случая когда FItems было просто указателем, или случая когда FItems было TList

GunSmoker

24-07-2015 12:24

developer   ~0016222

"мне не нравится добавление работы с расширением в ITileFileNameGenerator, так как я его от туда старательно убирал (по факту этот интерфейс нужно было переименовать в ITileNameGenerator). А логика по добавлению '.tile' к именам файлов должна жить внутри соответствующего типа тайлохранилища (отдельный класс или дополнительный параметр в конструктор TTileStorageFileSystem)"

Как в этом случае быть с экспортом в архив? Для генерации имени файла внутри архива там используется TileNameGenerator, а не хранилище (хранилище идёт только как источник). А расширение там вообще присовокупляется вручную - прямо в цикле. Создавать полноценный ITileStorage только для этого?

GunSmoker

24-07-2015 12:32

developer   ~0016223

Может сделать так: пусть TileNameGenerator поддерживает (новый) доп. интерфейс, в который вынести формирование имени файла. Пусть дефолтный TileStorage пытается запрашивать у TileNameGenerator этот новый интерфейс. Если он есть - делегировать формирования имени ему. Если нет - добавить расширение самому. Тогда не понадобится два новых класса для OsmAnd (TileStorage и TileStorageType). И экспорт в архив сможет правильно формировать имена файлов, не имея на руках полноценного TileStorage.

vdemidov

24-07-2015 12:43

manager   ~0016224

> Создавать полноценный ITileStorage только для этого?
Может и не совсем полноценный, а работающий только на запись, но ИМХО это правильней.
Сделать список всех доступных типов тайлохранилищ. У каждого есть набор доступных режимов работы: на импорт (однократный проход итератором), на экспорт (однократная запись), произвольный доступ на чтение, произвольный доступ на запись. И уже из этого списка формировать доступные для разных операций типа экспорта или параметров карты.
Тогда можно будет избавиться от отдельных экспортов в разные архивы. Это будет один экспорт в тайлохранилище с выбором типа этого тайлохранилища.
 
Но это так - мечты. Я пытаюсь постепенно к этом привести всю систему, но времени мало и часто отвлекаюсь на другие задачи. Поэтому и не настаивал на каких либо исправлениях.

vdemidov

24-07-2015 12:44

manager   ~0016225

>Может сделать так: пусть TileNameGenerator поддерживает (новый) доп. интерфейс, в который вынести формирование имени файла.
Не, оно того не стоит.

zed

26-07-2015 16:13

manager   ~0016229

Может уже стоит отметить тикет как отработанный? Или там планируется ещё что-то сделать?

Issue History

Date Modified Username Field Change
10-07-2015 20:33 GunSmoker New Issue
10-07-2015 20:36 GunSmoker Tag Attached: SQLite
10-07-2015 20:36 GunSmoker Tag Attached: склейка
10-07-2015 20:36 GunSmoker Tag Attached: экспорт
10-07-2015 20:59 zed Note Added: 0016120
12-07-2015 04:36 GunSmoker Note Added: 0016142
12-07-2015 06:40 zed Note Added: 0016143
12-07-2015 06:48 zed Note Added: 0016144
12-07-2015 10:14 vdemidov Note Added: 0016145
12-07-2015 16:10 GunSmoker Note Added: 0016146
12-07-2015 16:14 GunSmoker Note Added: 0016147
12-07-2015 16:24 GunSmoker Note Edited: 0016146
12-07-2015 16:27 GunSmoker Note Edited: 0016146
12-07-2015 16:29 GunSmoker Note Edited: 0016146
12-07-2015 17:08 zed Note Added: 0016148
12-07-2015 17:23 zed Note Added: 0016149
12-07-2015 18:00 GunSmoker Note Added: 0016150
12-07-2015 18:39 zed Note Added: 0016151
12-07-2015 19:32 GunSmoker Note Added: 0016152
12-07-2015 19:52 GunSmoker Note Added: 0016153
13-07-2015 00:19 GunSmoker Note Added: 0016154
13-07-2015 01:34 GunSmoker Note Added: 0016155
13-07-2015 02:05 zed Note Added: 0016156
13-07-2015 02:11 zed Assigned To => GunSmoker
13-07-2015 02:11 zed Status new => assigned
13-07-2015 02:11 zed Product Version .Nightly => 141212
13-07-2015 02:11 zed Target Version => 150915
18-07-2015 09:43 GunSmoker Note Added: 0016172
18-07-2015 10:00 zed Note Added: 0016173
19-07-2015 04:10 GunSmoker Note Added: 0016174
19-07-2015 07:58 zed Note Added: 0016175
19-07-2015 09:22 zed Note Added: 0016176
19-07-2015 15:06 GunSmoker Note Added: 0016177
21-07-2015 04:37 GunSmoker Note Added: 0016191
21-07-2015 05:22 zed Note Added: 0016192
21-07-2015 05:36 GunSmoker Note Added: 0016193
21-07-2015 07:30 vdemidov Note Added: 0016199
21-07-2015 08:16 GunSmoker Note Added: 0016201
21-07-2015 08:22 vdemidov Note Added: 0016202
21-07-2015 11:32 zed Note Added: 0016206
21-07-2015 11:37 zed Note Added: 0016207
23-07-2015 07:01 GunSmoker Note Added: 0016219
24-07-2015 09:54 GunSmoker Note Added: 0016220
24-07-2015 10:29 vdemidov Note Added: 0016221
24-07-2015 12:24 GunSmoker Note Added: 0016222
24-07-2015 12:32 GunSmoker Note Added: 0016223
24-07-2015 12:43 vdemidov Note Added: 0016224
24-07-2015 12:44 vdemidov Note Added: 0016225
26-07-2015 16:13 zed Note Added: 0016229
26-07-2015 17:11 vdemidov Status assigned => resolved
26-07-2015 17:11 vdemidov Fixed in Version => 150915
26-07-2015 17:11 vdemidov Resolution open => fixed
31-07-2015 11:56 vdemidov Relationship added related to 0000325
31-07-2015 12:27 vdemidov Relationship added related to 0001680
03-08-2015 08:43 vdemidov Relationship added related to 0002779
08-08-2025 13:24 zed Category Хотелка => Хотелка / Feature request