Форум по Delphi программированию

Delphi Sources



Вернуться   Форум по Delphi программированию > Все о Delphi > Мультимедиа
Ник
Пароль
Регистрация <<         Правила форума         >> FAQ Пользователи Календарь Поиск Сообщения за сегодня Все разделы прочитаны

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #1  
Старый 25.05.2013, 22:46
xabik xabik вне форума
Прохожий
 
Регистрация: 08.05.2012
Сообщения: 6
Репутация: 10
По умолчанию Перемещение + Масштабирование

Здравствуйте уважаемые форумчане.

Такой вот вопросик назрел в связи с разрабатываемой программой, связанный с графикой.

В моей программе на холсте TImage отрисовываются различные объекты. Данные объекты состоят из точек, имеющих координаты. Точки соединяются линиями. И вот задумал я сделать масштабирование и перемещение изображение холста с помощью мыши. Ну то есть колесико крутим меняется масштаб, зажимаем клавишу и тащим, изображение холста движется с мышью. Данные действия я реализовал простыми математическими операциями - перемещение добавлением к координатам точек dx и dy, масштабирование умножением координат точек на dz. При всем при этом изначальные координаты точек остаются теми же. Просто в процедуру рисования на холсте я передаю параметры dx, dy, dz, которые являются глобальными переменными, которые в зависимости от действий пользователя меняются. Ну то есть зажал пользователь клавишу и подвинул мышь на 100 px вправо и 50 px вниз, dx стал равен 100 dy стал равен 50. Затем пользователь подвинул мышь вверх на 20 px и влево на 30 px и dx стал равен 70, а dy 30. При масштабировании же при прокрутке колесика мышки вверх на 3 деления dz становится равным 0,7, затем если прокрутить колесо мыши вниз на 5 делений то равным 1,2.

По отдельности эти операции работают замечательно. А вот если вместе то беда все координаты сбиваются. Можно было бы решить данную проблему путем запоминания нового значения координаты как после перемещения так и после масштабирования, но вся беда в том что после масштабирования не всегда получается то что было изначально. Т.е. когда мы умножаем координаты на множитель dz мы же должны округлить получившееся значение что бы вывести его на холст. И в результате сжав и развернув изображение мы можем получить не то что было в начале. Поэтому изначальные координаты приходится хранить.
Теперь допустим пользователь сначала передвинул изображение, потом сжал его, а затем передвинул и расжал масштаб. Уверяю получится не совсем то что задумывалось изначально.

Вот как написать процедуру, которая всегда корректно отображает положение объектов и их масштаб. Для более красочного понимания того что я здесь понаписал зайдите на любую версию карт - Gooogle, Yandex и т.д. и попробуйте подвигать и помасштабировать их. Всегда все корректно. А как это работает не пойму.
Ответить с цитированием
  #2  
Старый 25.05.2013, 23:46
Аватар для Freeman
Freeman Freeman вне форума
Местный
 
Регистрация: 05.10.2012
Адрес: Санкт-Петербург
Сообщения: 577
Версия Delphi: 6
Репутация: выкл
По умолчанию

Цитата:
Сообщение от xabik
зайдите на любую версию карт - Gooogle, Yandex и т.д. и попробуйте подвигать и помасштабировать их. Всегда все корректно.
Потому что их авторы читали учебники по ООП и понимали их. Ибо описанное тут приведено в качестве базового примера более чем в половине учебников по программированию, где рассказываются основы ООП.

Суть в том, что исходную картинку нужно хранить в виде списка объектов и не "портить" каждый раз при движении и масштабировании. Вместо этого хранить два числа -- значения масштаба по X и Y, пересчитывать их каждый раз при изменении масштаба, после чего перегенерировать видимую картинку из неизменного исходного списка.

Хотел было пример написать, но лень. Читайте учебники.
Ответить с цитированием
  #3  
Старый 26.05.2013, 00:52
xabik xabik вне форума
Прохожий
 
Регистрация: 08.05.2012
Сообщения: 6
Репутация: 10
По умолчанию

Цитата:
Сообщение от Freeman
Потому что их авторы читали учебники по ООП и понимали их. Ибо описанное тут приведено в качестве базового примера более чем в половине учебников по программированию, где рассказываются основы ООП.

Суть в том, что исходную картинку нужно хранить в виде списка объектов и не "портить" каждый раз при движении и масштабировании. Вместо этого хранить два числа -- значения масштаба по X и Y, пересчитывать их каждый раз при изменении масштаба, после чего перегенерировать видимую картинку из неизменного исходного списка.

Хотел было пример написать, но лень. Читайте учебники.


То что Вы тут понаписали не внесло никакой ясности.

1. Объекты (т.е. координаты точек этих объектов) я не порчу. Если Вы внимательно прочли, а Вы этого не сделали, координаты остаются неизменными.
2. В каких конкретно книгах написано про это? Пожалуйста конкретно.
3. Приемами ООП владею. Но с координатами до сих пор в голове путаница.

Последний раз редактировалось xabik, 26.05.2013 в 00:56.
Ответить с цитированием
  #4  
Старый 26.05.2013, 01:15
Аватар для Freeman
Freeman Freeman вне форума
Местный
 
Регистрация: 05.10.2012
Адрес: Санкт-Петербург
Сообщения: 577
Версия Delphi: 6
Репутация: выкл
По умолчанию

Прошу показать код вывода.
Ответить с цитированием
  #5  
Старый 26.05.2013, 01:28
xabik xabik вне форума
Прохожий
 
Регистрация: 08.05.2012
Сообщения: 6
Репутация: 10
По умолчанию

Описание записи точки. Думаю можно обойтись и записями.

Код:
Dot = record
  x,y,xz,yz:integer;
  TypeDot:byte;
  ID:int64;
end;

ArrDot:array of Dot;

Описание процедуры пересчета координат при масштабировании

Код:
procedure ResizeMap(df:extended);
var i:integer;
begin
  for i:=0 to High(ArrDot) do begin
    ArrDot[i].xz:=Round(ArrDot[i].x*df);
    ArrDot[i].yz:=Round(ArrDot[i].y*df);
  end;
end;

Описание процедуры пересчета координат при перемещении

Код:
procedure MoveMap(dx,dy:integer);
var i:integer;
begin
  for i:=0 to High(ArrDot) do begin
    ArrDot[i].xz:=ArrDot[i].x+dx;
    ArrDot[i].yz:=ArrDot[i].y+dy;
  end;
end;

Вывод осуществляется по координатам xz и yz
Ответить с цитированием
  #6  
Старый 26.05.2013, 01:39
Аватар для YVitaliy
YVitaliy YVitaliy вне форума
Местный
 
Регистрация: 14.12.2011
Сообщения: 481
Версия Delphi: Borland Delphi7
Репутация: 17
По умолчанию

Вот таков пример работает? У тебя написано одно (о сохранении координат), а здесь ты их изменяешь. Изменение должно происходить только при выводе на экран.
Вложения
Тип файла: rar tst18.rar (1.9 Кбайт, 31 просмотров)
Ответить с цитированием
  #7  
Старый 26.05.2013, 02:04
xabik xabik вне форума
Прохожий
 
Регистрация: 08.05.2012
Сообщения: 6
Репутация: 10
По умолчанию

Я не уверен, но у Вас всё работает кажется правильно. Т.е. пересчитывается из начальных координат. Спасибо. Завтра разберусь с кодом. И пойму свои ошибки. А насчет изменения при выводе, ну тык начальные то координаты хранятся не в xz, yz, а в x и y. В любом случае большое Спасибо!!!
Ответить с цитированием
  #8  
Старый 26.05.2013, 02:13
Аватар для Freeman
Freeman Freeman вне форума
Местный
 
Регистрация: 05.10.2012
Адрес: Санкт-Петербург
Сообщения: 577
Версия Delphi: 6
Репутация: выкл
По умолчанию

Цитата:
Сообщение от xabik
Вывод осуществляется по координатам xz и yz
Это ключевое слово. Стало быть, исходные координаты не портятся. По крайней мере, в приведенном коде. В реальном коде нигде присвоения xz и yz исходным координатам нет?

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

Можно либо перейти на вещественные xz и yz, либо оперировать дробными пикселями, как это делает формат Flash (SWF). Целому пикселю соответствует изображение при максимальном приближении, а при выводе делится на масштаб и округляется. Не помню, возможны ли в SWF масштабы не в степенях двойки.

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


Delphi Sources

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB-коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход


Часовой пояс GMT +3, время: 10:05.


 

Сайт

Форум

FAQ

RSS лента

Прочее

 

Copyright © Форум "Delphi Sources" by BrokenByte Software, 2004-2023

ВКонтакте   Facebook   Twitter