-
Доброго времени суток. Суть задачи: Работа с картой. максимальный размер карты: 16160х14140 пикселей. вывод топоосновы и рисование на ней, разного типа обьектов. Реализация: Карта разбита на квадраты 8х7, в макимальном разрешении размер квадрата 2020х2020пик. в минимальном 202х202. Для масштабирования созданы карты разной степени детализации размерами 202, 404, 606, 808, 1010, 1212, 1414, 1616, 1818, 2020 пикселей, помещены в соотвествующие папки на диске. По скольку грузить целую картинку очень ресурсозатратно реализован вывод только видимой области. Прокрутка реализована посредством scrollbar получаем позицию ползунка и вычисляем диапазон видимой области.
procedure Tform1.ris(Sender: TObject; x1,y1,x2,y2,xs,ys:integer); //получаем картинку по ширине имейджа var polosa,ykt,xp,yp,sdx,sdy,y,x,kvadrat,xr1,yr1,xr2,yr2:integer; rx1,rx2,ry1,ry2,nx1,nx2,ny1,ny2:integer; JpegIm: TJpegImage; bm_razova,bm_razova1:tbitmap; begin polosa:=round(2020*combobox1.Tag/100); //в комбобоксе текущий масштаб и соответственно имя папки где лежат карты (10,20. //..90,100)
bm_razova := TBitmap.Create; bm_razova.PixelFormat:=pf24Bit; bm_razova.Width:=image1.Width; bm_razova.Height:=image1.Height;
ykt:=0; xp:=x1; yp:=y1; sdx:=0; sdy:=0;
for y:=((y1 div polosa)+1) to ((y2 div polosa)+1) do begin xp:=x1; sdx:=0; for x:=((x1 div polosa)+1) to ((x2 div polosa)+1) do begin kvadrat:=N_kvadrat(x,y);//получаем номер квадрата который попадает в видимый диапазон xr1:=xp; yr1:=yp; if x2<mass[kvadrat].xk2 then xr2:=x2 else xr2:=mass[kvadrat].xk2; if y2<mass[kvadrat].yk2 then yr2:=y2 else yr2:=mass[kvadrat].yk2; xp:=xr2; ykt:=yr2; karta.Close; karta.SQL.Clear; karta.SQL.Add('select * from karta where x=:x and y=:y'); karta.ParamByName('x').Asinteger:=x; karta.ParamByName('y').Asinteger:=y; karta.Open; bm_razova1 := TBitMap.Create; JpegIm := TJpegImage.Create; JpegIm.LoadFromFile(ini.readstring('base','karta','no')+'/'+inttostr(combobox1.tag)+'/'+karta.Fields[3].asstring+'.jpg'); bm_razova1.Assign(JpegIm); JpegIm.Destroy; if xr1>=polosa then xr1:=xr1-mass[kvadrat].xk1; if yr1>=polosa then yr1:=yr1-mass[kvadrat].yk1; if xr2>=polosa then xr2:=xr2-mass[kvadrat].xk1; if yr2>=polosa then yr2:=yr2-mass[kvadrat].yk1; // область вырезания rx1:=xr1; ry1:=yr1; rx2:=xr2-xr1; ry2:=yr2-yr1;
// область в которую помещаем nx1:=sdx; ny1:=sdy; nx2:=xr2-xr1; ny2:=yr2-yr1;
bm_razova.Canvas.CopyRect(bounds(nx1,ny1,nx2,ny2),bm_razova1.Canvas,bounds(rx1,r y1,rx2,ry2)); bm_razova1.Free; sdx:=sdx+(xr2-xr1); end; yp:=ykt; sdy:=sdy+(yr2-yr1); end; image1.Picture.Assign(bm_razova); bm_razova.Free; end;
Все работает, но не удовлетворяет скорость отображения и прокрутки карты.
Вопрос: В каком направлении копать для оптимизации, или может стоит выбрать совсем другой подхо
-
Считать и думать.
Время декодирования порядка 100 тактов на пиксель. 100х2020х2020/2 ГГц=0,204 секунд С учетом вашего алгоритма. При прокрутке по диагонали надо декодировать 4 таких картинки. Т.е 1 секунда. Что долго!
Выход уменьшить максимальную картинку. В 10 раз. Т.е размер картинке надо не более 674х674 пикселей.
Поэтому совет делай-те как все. Бить карту на кусочки по 512х512, а ещё лучше 256х256. Но даже это большая нагрузка на процессор. Во время быстрой прокрутки, гораздо быстрее интерполировать картинку с верхнего уровня. Что позволит грузить картинки ещё реже.
Время позиционирования головки на диске 10-30 мс, среднее пусть 20 мс. Разобьём экран на 3х3 квадрата. При движении по диагонали надо подгрузить 7 файлов. Для чтения 7 файлов надо 20 мс*7=140 мс или 7 кадров в/с. Терпимым является менее 125 мс или более 8 кадров/с. А для комфортной надо 10-15 кадров/в
-
Надо кэшировать загруженные jpeg-и, а не грузить их на каждой перерисовке. Можно взять более быструю библиотеку, libJpeg-turbo или IJL. Неплохо бы подгружать картинки в отдельном потоке (или нескольких потоках, если через libJpeg-turbo), но это уже сложнее.
-
Если брать мониторы 22-24 -то прийдется делать расчет минимум по 42 квадратам размера 256х256 будет ли прирос по скорости, 42 обращения к диску расчет координат для вставки?
-
invis © куда кешировать, в память? Допустим обрабатываю область схождения 4 квадратов размером 2020х2020 - получается с каждого квадрата мне нужно вырезать только часть области и воссоздать в единой картинке, вы предлагаете 4 куска держать в памяти, или я не так понял?
-
Можно и больше 4-х. Выделить под это, скажем, 100 мб. Когда всё израсходуется - удалять из кэша наиболее "старые" картинки, т.е. которые давно использовались. Даже если только 4 хранить, уже должно быть лучше. При небольшом скролле карты у тебя рисуются в основном одни и те же картинки, в текущем варианте ты их каждый раз заново декодируешь, а это медленнее любой отрисовки. Хотя при подгрузке новых фрагментов всё равно будет подёргиваться, без многопоточности этого сложно избежать.
Как вариант, если не планируется увеличение размера карты, можно грузить всё сразу. 16160*14140 не такой уж гигантский размер, 870 Мб с учётом уменьшенных копий. Сейчас любой браузер не стесняется отожрать больше гигабайта...
-
> Если брать мониторы 22-24 -то прийдется делать расчет > минимум по 42 квадратам размера 256х256 будет ли прирос > по скорости, 42 обращения к диску расчет координат для вставки?
Нету тут 42. При прокрутке подгружается только те что необходимо, а именно новые. Остальное держим в кэше и берёшь оттуда.
22-24 дюёма не важно главное разрешение 1280х1024 1280/256=5 1024/256=4 При движении в право влево надо будет подгрузить всего 5 картинок. При движении в верх вниз 4.
По диагонали 4+5+1=10 шт При движении скачком на новую позицию 4*5+10=30 шт
22-24 дюёма не важно главное разрешение 1280х1024 1280/512=3 1024/512=2 При движении в право влево надо будет подгрузить всего 5 картинок. При движении в верх вниз 4.
По диагонали 2+3+1=6 шт При движении скачком на новую позицию 3*2+6=12 шт
Замеров не делал точно сказать не могу.
Прирост будет так как диск тоже кеширует данные и оптимизирует запросы. С большим числом файлов конечно он справляется хуже чем с меньшем. Так что на вскидку 10 мс на чтение 1 файл, а может будет и лучше. Чтение 30*10=300 мс Декодирование 30*256*256*100/3ГГц=65 мс
Чтение 12*10=120 мс Декодирование 12*512*512*100/3ГГц=105 мс
Будет немного притормаживать, но это вполне терпимо - несильно бросается в глаза. Хотите быстрее делайте прогрессивную загрузку. Грузите с верхнего уровня интерполируйте. Отображаете. Пока пользователь не понял погружаете с основного слоя.
Параллельность вещь полезная. А с ней насколько я понял, вы незнакомы и долго будете разбираться.
-
> invis © (14.02.16 23:31) [5]
> Как вариант, если не планируется увеличение размера карты, > можно грузить всё сразу. 16160*14140 не такой уж гигантский > размер, 870 Мб с учётом уменьшенных копий. Сейчас любой > браузер не стесняется отожрать больше гигабайта...
+1 к этому варианту. на современных машинах минимум 4 Гб памяти уже лет 5 ставят. Даже если не все грузить, то кэшировать точно, см. гугл-мапс и яндекс-карты.
-
Eraser © (22.02.16 15:23) [7]
На D7 память крайне быстро кончится. Мало ли что там на машинах ставят, у 32-х битного приложения свои лимиты.
|