Notes |
|
(0016120)
|
zed
|
10-07-2015 20:59
|
|
>непонятно, что мешает сделать
Ничего не мешает. Как говорится - бери да делай :) |
|
|
|
Если это, типа, подколка, то лично мне мешает полное незнание предметной области. Есть подозрение, что с какими-нибудь координатами и типами хранилища я так наворочу - мама не горюй. Но пока пытаюсь разобраться. |
|
|
(0016143)
|
zed
|
12-07-2015 06:40
|
|
Это правда жизни - вопрос "что мешает?" можно задать в любом открытом тикете и ответ будет точно таким же. И незнание предметной области не является веской причиной, чтобы ничего не делать. Всё прекрасно познаётся "в процессе", так что велкам.
По поводу "наворочу": глядя на пример того же RMaps, я думаю, будет трудно наворотить. Для комбинирования слоёв с картой используется TBitmapLayerProviderMapWithLayer, который инициализируется картой и слоем (или списком слоёв), а потом у него последовательно запрашиваются тайлы в нужной проекции. Далее, результат конвертируется в нужный формат при помощи IBitmapTileSaver (который возвращает фабрика TBitmapTileSaveLoadFactory) и сохраняется в хранилище или ещё куда угодно. Главное понимать в какой проекции получился ваш тайл и какую проекцию ожидает/поддерживает хранилище или целевой формат, если речь о экспорте.
Проекцию вы може взять либо у исходного хранилища из которого читаете тайлы:
VGeoConvert := FTileStorage.CoordConverter;
VProjection := FProjectionFactory.GetByConverterAndZoom(VGeoConvert, FZoom);
Либо создать одну из 3-х доступных:
VGeoConvert := FCoordConverterFactory.GetCoordConverterByCode(
CGoogleProjectionEPSG,
CTileSplitQuadrate256x256
);
VProjection := FProjectionFactory.GetByConverterAndZoom(VGeoConvert, FZoom);
И в итоге, с координатами вам вообще не нужно иметь дела, да и тайлохранилища спрятаны за интерфейсами, так что вы даже не почувствуете разницы при записи в разные типы.
Если что-то не понятно, спрашивайте. |
|
|
(0016144)
|
zed
|
12-07-2015 06:48
|
|
Хороший пример создания IBitmapTileUniProvider можно подсмотреть в склейке, в функции TfrMapCombine.GetProvider - там на выбор можно либо наложить все отображаемые слои, либо один конкретный, ну или вообще не накладывать. Правда, в экспорте нужно учитывать, что если мы ничего не накладываем поверх карты и нас устраивает проекция и формат изображений тайлохранилища, то тайлы нужно передавать напрямую из хранилища, без лишней конвертации в битмапку. Т.е. этим провайдером не пользоваться. |
|
|
|
Вообще то, я давно планирую перевести экспорты оперирующие тайлами (JNX, сохранение в тайлохранилище и тд) на использование интерфейса ITileInfoUniProvider, у которого экспорт может запросить требуемый тайл с инофрмацией о типе и времени создания. А уже реализация этого провайдера может или напрямую передавать инфу из тайлохранилища, или склеивать и пределывать тайлы налету, или даже просто рендерить тайлы слоя заполнения или меток. Просто все руки никак не доходят сделать. |
|
|
(0016146)
|
GunSmoker
|
12-07-2015 16:10
(edited on: 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. Чем она специальна?
- Количество поясняющих комментариев угнетает :)
|
|
|
|
Кстати, с FastMM в FullDebugMode при закрытии вываливаются утечки, иногда - ошибки. Это так и должно быть? :) |
|
|
(0016148)
|
zed
|
12-07-2015 17:08
|
|
>в TThreadCopyFromStorageToStorage.ProcessTile загрузить тайл в bitmap
Копирование из хранилища в хранилище происходит на самом низком уровне и там нету никаких преобразований. Тупо перекидывается бинарь из одного в другое. Чтобы оперировать битмапами и проекциями, нужно подняться на уровень выше, до IMapType - это уже карта, у неё можно запрашивать битмапы в любой известной проекции. А брать из хранилища тайлы и самому пытаться их распаковать в битмап, не стоит. И TBitmapLayerProviderMapWithLayer оперирует как раз картами, его и нужно использовать.
>Тайлы всегда одинаковые по размеру
Пока что да.
>Как узнать, в каком формате нужно передавать (jpg/png)?
Можно взять Saver у карты, а можно спросить и пользователя. См. как это сделано в TfrExportRMapsSQLite.GetBitmapTileSaver, там как раз все варианты присутствуют.
>ITileStorage.GetTileInfoEx - аналогичный вопрос: в каком формате возвращает
Можно узнать какой из интерфейсов поддерживается: IContentTypeInfoBitmap или IContentTypeInfoVectorData и получить Saver/Loader. Далее, можно сравнить свой Saver с полученным. Так можно проверить формат, но не настройки сохранения, они могут отличаться.
>вижу упоминания CGoogleProjectionEPSG. Чем она специальна?
Ничем. Просто RMaps других не понимает, если правильно помню, вот и происходит принудительная конвертация при необходимости.
>при закрытии вываливаются утечки, иногда - ошибки
Возможно это 0002050 |
|
|
(0016149)
|
zed
|
12-07-2015 17:23
|
|
Советую сделать свой отдельный экспорт с функцией наложения слоёв и выбором результирующего хранилища, проекции, формата тайлов и т.д. Взять за основу всё тот же RMaps. Из копирования можно взять момент с созданием интерфейса целевого хранилища. Скомбинировать всё это и получится желаемый результат. А вкладка копирования, это всё же отдельная песня и копирование обычно не подразумевает изменения. Так что туда лучше не встревать, особенно учитывая, что там есть возможность копировать сразу пачку хранилищ (и оно копируется не в одно хранилище, а точно в такую же пачку, но уже в другом месте). |
|
|
|
Да-да, уже делаю две вкладки, одна - прямое копирование (как есть), вторая - с преобразованием (моё). |
|
|
(0016151)
|
zed
|
12-07-2015 18:39
|
|
А смысл прямого копирования? |
|
|
|
В смысле? Под "как есть" я имел в виду то, что сейчас делает вкладка "Скопировать". Там же прямое копирование тогда получается, или нет? |
|
|
|
> Возможно это 0002050
Похоже некоторые потоки не закрываются при выходе из программы. Или не успевают завершиться. Возможно не отпускается ссылка на поток? |
|
|
|
> Копирование из хранилища в хранилище происходит на самом низком уровне и там нету никаких преобразований. Тупо перекидывается бинарь из одного в другое.
1. Если источник - png, а сохраняется в jpg? Что тогда? Или получается, что формат хранилища не диктует формат файла?
2. Если не совпадают проекции источника/цели? Надо же конвертацию какую-то выполнить? |
|
|
|
Кажется, что-то получилось.
Сделал новую вкладку, сделал отдельный модуль с новым потоком, на вход - BitmapLayerProviderMapWithLayer, как в RMaps, и TileStorage, как в Copy. Копирует с наложением в выбранный формат хранилища - ОК. Результат такого "модифицирующего" копирования вроде совпадает с "прямым копированием" - по файловой структуре и координатам в тайлах (за исключением самого содержимого рисунков, конечно - но если убрать слой наложения, то совпадает и контент рисунков).
Но, похоже, с преобразованием координат между слоями что-то не то (??). Если копировать гугл+гугл = ОК, если гугл+яндекс = ОК, а если яндекс+гугл = срабатывает Assert в TBitmap32StaticFactory.BuildWithOwnBuffer (FBackEndByStatic.FBitmapStatic = nil). Вроде как цикл в TMapType.LoadBitmap не выполняется ни разу. Сложно отлаживать, т.к. почему-то в этом коде 2007-я виснет постоянно (вместе с ОС). |
|
|
(0016156)
|
zed
|
13-07-2015 02:05
|
|
>Под "как есть" я имел в виду
Ну вот мне и не понятно зачем делать тоже самое, что уже есть на другой вкладке. Разве что чисто потренироваться?
>Если источник - png, а сохраняется в jpg?
Как оно вдруг станет jpeg, если там нету конвертирования?
>Если не совпадают проекции источника/цели?
Источник и цель это кэш одной и той же карты, поэтому проекция там всегда одна. А вот если попытаться скопировать в кэш другой карты, то это уже на свой страх и риск, и нужно понимать что делаешь. Перепроецирования нету.
>а если яндекс+гугл = срабатывает Assert
Не видя кода, сложно сказать. Но "гугл+яндекс" это тоже разные проекции.
>2007-я виснет постоянно (вместе с ОС)
Я обычно использую XE2 при разработке, попробуй её. А D2007 только если приходится на старом железе в XP работать, ну и для проверки, что ночнушка соберётся. |
|
|
|
Я XE в основном использую. Под ней на хостовой машине всё отладил - нашёл у себя в коде ошибку. Теперь вроде всё работает. Пока, правда, особо не тестировал.
Теперь вопрос - эти изменения как и куда заливать? |
|
|
(0016173)
|
zed
|
18-07-2015 10:00
|
|
|
|
|
zed, а не подскажешь, вот в 0000780 просили кэш вида <ZOOM>\<Y>\<X>.png. Мне как раз он нужен для экспорта. Вроде как он реализован в u_TileFileNameGM3.pas и обзывается rsGlobalMapperBingCacheName = 'GlobalMapper Bing'. Вопрос: почему он не создаётся в u_TileStorageTypeListSimple.pas? |
|
|
(0016175)
|
zed
|
19-07-2015 07:58
|
|
Похоже, что про него просто забыли. Нужно добавлять. |
|
|
(0016176)
|
zed
|
19-07-2015 09:22
|
|
|
|
|
Гы, я его тоже восстановил и думал заливать это или нет :)
Я ещё поиграюсь немного. |
|
|
|
По основным исходникам - создал пул-реквест.
Но не могу сообразить, как правильно сделать внесение изменений в либы (requires)? Мне бы дефайны поправить для поддержки Delphi XE. Делаю форк и клон, вношу изменения, делаю коммит - а там же подхранилища, клиент хочет вносить изменения напрямую в ваши, а не в мой форк. |
|
|
(0016192)
|
zed
|
21-07-2015 05:22
|
|
>По основным исходникам - создал пул-реквест.
Тогда ждём резолюции от vdemidov-а.
Ты, кстати, зачем свой форк приватным сделал? Этот реквест вживую теперь фиг проверишь перед принятием.
>как правильно сделать внесение изменений в либы (requires)
Делаешь клон конкретной либы, делаешь туда пул-реквест, а как их принять в корневой репо (requires) уже наша задача.
В какую либу надо вносить изменения? |
|
|
|
> Ты, кстати, зачем свой форк приватным сделал? Этот реквест вживую теперь фиг проверишь перед принятием.
Я ж не знал :)
Поправил.
> Делаешь клон конкретной либы, делаешь туда пул-реквест, а как их принять в корневой репо (requires) уже наша задача.
Понял. У меня была проблема с поиском. Сейчас сделаю. |
|
|
|
Смотрю реквест. Ощущения двойственные. За первых три коммита вообще очень благодарен. Особенно за "Добавлены проверки на наличие указания выходного файла/папки перед началом работ по региону"
А вот к остальным есть претензии.
Во-первых, мне не нравится добавление работы с расширением в ITileFileNameGenerator, так как я его от туда старательно убирал (по факту этот интерфейс нужно было переименовать в ITileNameGenerator). А логика по добавлению '.tile' к именам файлов должна жить внутри соответствующего типа тайлохранилища (отдельный класс или дополнительный параметр в конструктор TTileStorageFileSystem)
Во-вторых, лучше было закладку копирования вообще не трогать, а добавить экспорт в тайлохранилище и там уже выбирать тип тайлохранилища в том числе и добавленный отдельно 'OsmAnd+ Tiles'
Ну и в-третьих, хорошо бы причесывать коммиты перед созданием пул реквеста, что бы по возможности не было некомпилируемых по-отдельности коммитов как получились два предпоследних.
Но, если сильно лень переделывать и так приму, так как пользы от реквеста все-таки гораздо больше чем моих претензий. |
|
|
|
Могу переделать вот это, но, наверное, будет это не ранее след. выходных:
"Во-первых, мне не нравится добавление работы с расширением в ITileFileNameGenerator, так как я его от туда старательно убирал (по факту этот интерфейс нужно было переименовать в ITileNameGenerator). А логика по добавлению '.tile' к именам файлов должна жить внутри соответствующего типа тайлохранилища (отдельный класс или дополнительный параметр в конструктор TTileStorageFileSystem)" |
|
|
|
Тогда принимаю как есть, а там разберемся. |
|
|
(0016206)
|
zed
|
21-07-2015 11:32
|
|
Обращаю внимание на:
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. В гуе на вкладке скопировать не вмещаются контролы, окно нужно растянуть по вертикали, чтобы по-умолчанию всё было видно. |
|
|
(0016207)
|
zed
|
21-07-2015 11:37
|
|
И вопрос по поводу пул-реквеста в alcinoe - там точно эти фиксы необходимы? |
|
|
|
Замечания поправлю.
> там точно эти фиксы необходимы?
Да, конечно. В XE же нет namespace-в для стандартных модулей. Они появились только в XE2. Так что для XE2 - "System.AnsiStrings.ЧТОТО", для XE - "AnsiStrings.ЧТОТО". |
|
|
|
Можно вопрос: зачем пишется код вида:
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 - динамический массив из интерфейсов.
Это для упрощения отладки? Или остатки от старого не-интерфейсного кода? |
|
|
|
Скорее всего остатки старого неинтерфейсного кода, или случая когда FItems было просто указателем, или случая когда FItems было TList |
|
|
|
"мне не нравится добавление работы с расширением в ITileFileNameGenerator, так как я его от туда старательно убирал (по факту этот интерфейс нужно было переименовать в ITileNameGenerator). А логика по добавлению '.tile' к именам файлов должна жить внутри соответствующего типа тайлохранилища (отдельный класс или дополнительный параметр в конструктор TTileStorageFileSystem)"
Как в этом случае быть с экспортом в архив? Для генерации имени файла внутри архива там используется TileNameGenerator, а не хранилище (хранилище идёт только как источник). А расширение там вообще присовокупляется вручную - прямо в цикле. Создавать полноценный ITileStorage только для этого? |
|
|
|
Может сделать так: пусть TileNameGenerator поддерживает (новый) доп. интерфейс, в который вынести формирование имени файла. Пусть дефолтный TileStorage пытается запрашивать у TileNameGenerator этот новый интерфейс. Если он есть - делегировать формирования имени ему. Если нет - добавить расширение самому. Тогда не понадобится два новых класса для OsmAnd (TileStorage и TileStorageType). И экспорт в архив сможет правильно формировать имена файлов, не имея на руках полноценного TileStorage. |
|
|
|
> Создавать полноценный ITileStorage только для этого?
Может и не совсем полноценный, а работающий только на запись, но ИМХО это правильней.
Сделать список всех доступных типов тайлохранилищ. У каждого есть набор доступных режимов работы: на импорт (однократный проход итератором), на экспорт (однократная запись), произвольный доступ на чтение, произвольный доступ на запись. И уже из этого списка формировать доступные для разных операций типа экспорта или параметров карты.
Тогда можно будет избавиться от отдельных экспортов в разные архивы. Это будет один экспорт в тайлохранилище с выбором типа этого тайлохранилища.
Но это так - мечты. Я пытаюсь постепенно к этом привести всю систему, но времени мало и часто отвлекаюсь на другие задачи. Поэтому и не настаивал на каких либо исправлениях. |
|
|
|
>Может сделать так: пусть TileNameGenerator поддерживает (новый) доп. интерфейс, в который вынести формирование имени файла.
Не, оно того не стоит. |
|
|
(0016229)
|
zed
|
26-07-2015 16:13
|
|
Может уже стоит отметить тикет как отработанный? Или там планируется ещё что-то сделать? |
|