LINUX.ORG.RU

CADы как в программах устроен механизм масштабирования и скроллинга?


0

2

Доброго времени суток, заранее извиняюсь если немного сумбурно определил тему, просто пока ещё сам не могу её точно сформулировать, ибо она состоит из кучки маленьких вопросов «как» и «почему» и целостной картины в моей голове пока не имеет. В попытке собрать всё воедино и понять, что да как, создаю эту тему. Если кто разрабатывал подобные приложения, прошу поделиться опытом :)

Итак, пытаюсь понять, как устроены программы типа CAD-ов(в плане вывода на экран), в которых приходится что-либо рисовать. Например, программы для рисования электрических схем, или каких либо планов домов и.т.д. Интересует в них следующее: как в них реализуется масштабирование и скроллинг. Если с масштабированием более-менее понятно, т.е взяли все размеры и координаты, помножили на некоторое число(scale factor), получили новые размеры и координаты, отрисовали и вот вроде бы всё стало другого размера. То со скроллингом есть несколько вопросов:

  • Как работает скроллинг: у нас есть некоторое виртуальное окно и окно, которое мы видим на экране(например Frame). Если виртуальное окно больше клиентской части фрейма, то появляются скроллбары. Так? Теперь вопрос, в каких единицах обычно задаётся размер виртуального окна и по какому принципу этот размер выбирается? Т.е этот размер может быть бесконечным, или он привязывается, скажем, к размеру листа A4(3,2,1,0), переведённому в единицы измерения размеров вирт. окна?
  • При скроллинге, когда пользователь дёргает за скроллбар, картинка должна проскроллиться на некоторую величину, как обычно вычисляется эта величина или просто от фонаря задаётся(задали наобум, скажем 10 пикселей)?
  • Какую систему координат обычно применяют в таких программах и откуда вести отсчёт координат? Т.е брать ли мне центр начала координат в центре экрана, или это должен быть верхний левый угол экрана? Правильно ли, что окно на экране(Frame), который «плавает» по виртуальному окну, также имеет свои координаты, которые как раз и отсчитываются от верхнего левого угла вирт. окна?
  • Я так понимаю, что когда человек в этой программе рисует что-то, то всё рисование вычисление должно вестись в каких-то внутренних единицах, которые потом переводятся в реальные единицы устройства, на которые картинка выводится, правильно? Что обычно берётся за внутреннюю единицу и как переводится в единицы устройства?

В данном вопросе я сознательно дистанцировался от указания конкретно фреймворка/библиотеки или ЯП, потому как думаю, что в граф. приложениях принцип идентичен везде, независимо от инструментария. Если нужна конкретика, то я ориентируюсь на wxWidgets. Пока вроде всё, если появятся вопросы, буду их задавать по ходу темы :)

★★★★★

Скроллинг в CAD? Т.е. мышкой прокрутили и окно съехало на n единиц вниз/вверх/вправо/влево? А масштабирование тогда как? Что хочу сказать - скроллинг лишнее. Просто зум и двигаем по осям. Не?

Размер окна, наверное, удобнее подгонять под стандарты А(0/1/2/3/etc) - это если потом собираемся печатать. А если тридэ - тогда надо делать как-то соразмерно метрической/имперской системе. На счёт бесконечности - задать максимум, например 1 000хА0.

Отсчёт начала координат только из центра окна/экрана, никак не сверху/снизу/и т.п. Так гораздо удобнее.

Ни разу не программист, всё вышесказанное основывается на собственном опыте _пользования_ такими программами и собственном представлении об их работе. Может будет полезно, а может просто проигноришь. GLHF anyways.

anonymous ()

большинство пунктов описываются в документации графической библиотеки/оконного менеджера, это всё по их части

Harald ★★★★★ ()

Как работает скроллинг...

Я ориентировался на размер листа (File / Page Setup...). Можно сделать так, чтобы при масштабе 1:1 было 100% соответствие по размеру (все данные обычно доступны), а можно просто забить на точность, ориентируясь на какой-то типичный размер dpi. Во многих случаях картинка на экране необязана быть точной, а вот на печати крайне желательна точность.

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

При скроллинге, когда пользователь дёргает за скроллбар, картинка должна проскроллиться на некоторую величину, как обычно вычисляется эта величина или просто от фонаря задаётся(задали наобум, скажем 10 пикселей)?

Здесь, кто на что горазд. Стандарта нет, по крайней мере, на винде. Сделай так, чтобы было удобно и плавно. Можно еще подсмотреть в Java Swing и SWT. У первого исходники много лучше.

Какую систему координат обычно применяют в таких программах и откуда вести отсчёт координат?

Зависит от твоей задачи, но какая-то система координат быть должна. Точно не система монитора.

Что обычно берётся за внутреннюю единицу и как переводится в единицы устройства?

В MFC и WinAPI был какой-то страх божий на эту тему. В GDI+, Swing, SWT, CAPI с этим должно быть полегче. Деталей уже не помню, но это не должно быть большой проблемой, если есть четкий порядок с системами координат (см. начало).

dave ★★★★★ ()
Ответ на: комментарий от nanoolinux

Вопрос не в этом. Я пытаюсь прояснить, на каком принципе основан скроллинг вообще, как он реализован в приложениях, откуда вести отсчёт координат, в каких единицах это всё делать.

Просто зум и двигаем по осям. Не?

Если просто зум, то тогда изображение может не влезть в окно(frame), тогда будет скроллинг.

xterro ★★★★★ ()

Какую систему координат обычно применяют в таких программах и откуда вести отсчёт координат?

Классически делается две системы: мировая и видовая. Мировая - это твоя сцена(схема, дом и т.п.) у неё фиксированное начало координат. Видовая - это система координат которая будет использоваться на твоём устройстве вывода, центр у данной системы должно быть удобно держать в виде точки с координатами в мировой системе координат и двигать его при скроллинге\зуме. Двигается он довольно просто: http://gendocs.ru/docs/29/28681/conv_3/file3.pdf (тут можно прочитать про координаты и про преобразования координат, см. во второй половине начиная с Преобразования объектов).

Norgat ★★★★★ ()
Последнее исправление: Norgat (всего исправлений: 1)
Ответ на: комментарий от Norgat

Т.е я так понимаю, центр системы координат лучше располагать в центре окна(виртуального) и от него вести все отсчёты и измерения?

xterro ★★★★★ ()
Ответ на: комментарий от xterro

Т.е я так понимаю, центр системы координат лучше располагать в центре окна(виртуального) и от него вести все отсчёты и измерения?

Да, примерно так. Центр координат мировой системы ты фиксируешь и относительно него у тебя производятся все действия со сценой (набором линий и плоскостей). Это позволит довольно просто реализовать сохранение и загрузку сцен из файлов.

Второе, для отображение используется идея Viewport'а (http://ru.wikipedia.org/wiki/Порт_просмотра). Т.е. у тебя есть точка, в мировой системе координат в которой у тебя находится экран и через которую у тебя пользователь будет смотреть на сцену. Центр viewport'а - это центр экрана отображения (там добавится ещё небольшое смещение, но это уже детали реализации).

В результате, можно свести зум к отдалению точки viewport'а, скроллинг к сдвигу viewport'а. Это довольно просто и в бытность студентами такие вещи писали за пару дней. Намного сложнее решить задачи сортировки отображаемых объектов (если не делать, то могут возникать артефакты на картинке) и отсечение невидимых линий(если не делать, то даст просадку по производительности на большой сцене).

P.S. советую найти какой-нибудь курс компьютерной графики на интуите и пройтись по нему. Многие моменты должны проясниться.

Norgat ★★★★★ ()
Последнее исправление: Norgat (всего исправлений: 1)
Ответ на: комментарий от xterro

нет, координата 0,0 - это традиционно левый верхний угол.

anonymous ()

Если с масштабированием более-менее понятно, т.е взяли все размеры и координаты, помножили на некоторое число(scale factor), получили новые размеры и координаты, отрисовали и вот вроде бы всё стало другого размера.

Немного не так, все размеры и координаты хранятся в некоторых относительный единицах. Масштаб задается отношением этих относительных единиц к пикселям/миллиметрам/дюймам... При изменение масштаба происходит перерасчет относительных координат в пиксели и перерисовка изоражения (рендеринг).

TDrive ★★★★★ ()
Ответ на: комментарий от TDrive

Масштаб задается отношением этих относительных единиц к пикселям/миллиметрам/дюймам...

Не совсем понял, как это? (

xterro ★★★★★ ()
Ответ на: комментарий от xterro

Не совсем понял, как это? (

Это означает, что пока фигуры отображаются на экране, их размеры можно хоть в «попугаях» измерять. Реальные размеры нужны только при привязывании фигуры к реальному миру. К примеру, при печати на принтере. Вот тогда вам и придется преобразовывать ваших «попугаев» в реальные еденицы измерения. Делаете равенство 1 «попугай» = 1 милиметр или 1 дюйм и вашу фигуру можно распечатать на принтере. Ставите 1 «попугай» = 1 пиксель и фигуру можно сохранить в растровый файл с четко определенными размерами. А поставите равенство 1 «попугай» = 10 километров, и туже самую фигуру придется разве что на луне лазером выжигать. Так что, пока фигура на экране, она должна считаться в виртуальных единицах.

anonymous ()
Ответ на: комментарий от dave

Можно ещё вопрос, когда мы меняем масштаб(например колёсиком прокрутили, или в меню выбрали), то это получается мы также меняем размер виртуального окна?

xterro ★★★★★ ()

Чтобы не париться, можно сделать проще (правда, это будет быдлокод в стиле "автокада"): схема рисуется при помощи OpenGL, масштабирование задается изменением расстояния от "глаза" до плоскости, в которой рисуется схема, скролл задается перемещением "глаза" параллельно этой плоскости.

Элементарно, но жрет как ни в себя.

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

Anon ()
Ответ на: комментарий от xterro

Зависит от реализации.

Сейчас я обычно делаю так, что просто меняю размер вложенного виджета/контрола/пэйна, который лежит, например, внутри ScrolledComposite, а сама гуишная библиотека (Swing, SWT) уже обеспечивает прокрутку, показывает полосы этой прокрутки и т.п. Это самый простой способ. Я лишь правильно центрую при масштабировании, а также меняю систему координат при рисовании и обработке мышиных событий (перенос и масштабирование). Минусом является то, что у некоторых библиотек есть физическое ограничение на максимальный размер (как я понял, в Swing его нет, но есть в Windows Forms и, возможно, GTK).

А раньше на связке Windows Forms и GDI+ у меня была хитроумная система с дополнительной виртуализациией, благодаря чему диаграммы могли иметь практически неограниченный размер при том, что Control вполне ограничен по размеру, особенно при применении двойной буферизации (нужна память для сохранения текущего изображения Control или его части). Как оказалось, такое нахрен никому не нужно было.

dave ★★★★★ ()
Последнее исправление: dave (всего исправлений: 1)

Дружище, ты не там вопрос задаешь, сейчас тебе программисты (ну это в лучшем случае) расскажут, как надо писать кады. Сразу скажу, за начало координат в центре экрана убивать долго и мучительно.
Если твое ПО для сегмента СНГ, то открой для себя ГОСТ, посмотри что и как чертися, потом думай над реализацией, незабудь что есть абсолютные и относительные координаты и они активно используются. Создать кад без координатной сетки можно, но не нужно такова специфика, потом файлы уйдут в документооборот на пройзовдство и т.д. И уже, допустим, оператор ЧПУ будет тебя вспоминать, за твой кад без секи, разнообразными словами.
Собственно ответ на твои зумы и скролы прост, задайся единицами измерения, раскинь сетку на экран, посторой формулы зума и скрола твоих попугаев связанных скажем с метрической системой (я бы не забыл и про дюймы) для буфера видеовывода окна. Потом поиграй с сеткой, погляди что получилось.
А вообще если от черчения далек, то брось затею или найди человека который разбирается. Иначе выйдет очередной велосипед, на котором можно будет работать, только выучив кучу несуразиц мануала и допилив напильником конфиги всего что только можно.

anonymous ()

Да забыл, к размеру листа нет смысла привязываться, это частный случай, общей задачи.

anonymous ()
Ответ на: комментарий от anonymous

Не, вопрос не в этом. Сейчас передо мной стоит задача создать общий класс, который будет отвечать за масштабирование изображения, размеры, сетку, единицы измерения и т.д. А для чего он будет использоваться, для CAD-ов или ещё для чего, это уже вопрос отдельный. Сейчас занимаюсь тем, что укладываю всё по полочкам в голове, пытаясь понять что да как.

Прикидываю: у меня будет класс BaseScreen и класс CompView. BaseScreen это как раз класс, который отвечает за масштаб, размер сетки, хранит размер виртуального экрана. CompView это класс, наследник wxScrolledWindow и BaseScreen, это уже класс вьюпорта, т.е плавающее окно по «виртуальному». Он обрабатывает скролл ну и собственно представляет собой сам виджет, который потом уже можно положить во фрейм.

Да забыл, к размеру листа нет смысла привязываться, это частный случай, общей задачи.

А как тогда задавать размеры? От балды?

xterro ★★★★★ ()
Последнее исправление: xterro (всего исправлений: 1)
Ответ на: комментарий от xterro

А как тогда задавать размеры? От балды?

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

anonymous ()
Ответ на: комментарий от xterro

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

anonymous ()
Ответ на: комментарий от xterro

И да, по поводу какой из углов - начало координат. Не слушай этих «англичан», левый нижний наше все, ибо оси уходят вверх, вправо.

anonymous ()
Ответ на: комментарий от xterro

Ох уж, раз пошла такая пьянка. Зум делается относительно указателя мыши.

anonymous ()

Скажу как активный пользователь в прошлом и эпизодически теперь.

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

2. Использование именно скроллбара в моей практике и практике коллег крайне редко, думаю реализуют его только для совместимости навыков. Обычно все работают либо перемещением чертежа за точку, указанную средней кнопокй мыши, либо разного рода «зумом в рамку» в разных режимах. Например выбрав один из режимов такого зума, даешь мышью прямоугольник, после отпускания ЛКМ, эта прямоугольная область у тебя на весь экран. Либо в меню выбираешь другую команду, у тебя на весь экран - все объекты в пространстве листа, либо всё пространство модели. Эти методы быстрее, чем использование скролла. Не буду утверждать определенно, но возможно в последних версиях скроллбары по умолчанию отключены, можно включать из настроек ПО.

aludov ()

Описался - Рамка прибивается к пространству модели.

aludov ()
Ответ на: комментарий от anonymous

левый нижний наше все, ибо оси уходят вверх, вправо.

Да уж, наследие текстовых терминалов теперь делает совершенно невыносимой работу с графикой: выводить изображение ты должен OpenGL'ем, у которого начало координат в левом верхнем углу, а система левовинтовая, в то время как координаты на самом изображении заданы в правовинтовой системе с началом координат в центре или в левом нижнем углу. Сам помучился с выводом FITS'ов на экран!

Anon ()
Ответ на: комментарий от Anon

Тогда думаю, оставлю систему координат по умолчанию - верхний левый угол (0,0), оттуда и всё считать буду. Тогда получается что у плавающего по виртуальному окну фрейма, верхний левый угол будет не с координатами 0,0, а что-то другое.

xterro ★★★★★ ()
Ответ на: комментарий от xterro

Преобразование координат — дело элементарное. Главное — не забывай преобразовать левовинтовую систему в правовинтовую. Сам делай как хочешь, но вот пользователю надо чертить в нормальных правовинтовых координатах.

Ну, а преобразовывать реальные координаты в отображаемые просто: ты знаешь коэффициент увеличения, знаешь величину смещения — все, экранные координаты умножаем на увеличение и смещаем на смещение.

Anon ()
Ответ на: комментарий от xterro

Тогда думаю, оставлю систему координат по умолчанию - верхний левый угол (0,0), оттуда и всё считать буду

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

zamtmn ()
Ответ на: комментарий от Anon

экранные координаты умножаем на увеличение и смещаем на смещение.

fixed: экранные координаты умножаем матрицу перехода из одной СК в другую СК

zamtmn ()
Ответ на: комментарий от Anon

Без них в графике всеравно никуда, можно конечно сделать без них, но лучше чтоб сразу отложилось что надо их юзать))

zamtmn ()
Ответ на: комментарий от zamtmn

Не по теме, в либах вырожденные матричные вычисления уже запилили? А то было это в далеком 2000ом, модель писал в матрицах, а потом пришлось сворачивать вычисления в формулы ибо гонялось все на г.. мамонта.

anonymous ()
Ответ на: комментарий от anonymous

В OpenGL непосредственно матрицы и задаешь. GSL отлично матрицы умеет, но для такой элементарщины, как преобразования координат, GSL — как микроскопом гвозди.

Anon ()
Ответ на: комментарий от Anon

Попробую подвести промежуточный итог из той кучи что я тут намесил и что понял:

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

Как то так :)

xterro ★★★★★ ()
Ответ на: комментарий от zamtmn

Да уже ответили, погляжу попозже, чтоб быт в курсе.

anonymous ()
Ответ на: комментарий от xterro

Система координат модели это по сути и есть система координат окна(с началом в верх. лев. углу вирт. окна)

и для кого писали, что пользователь работает в человеческих осях, а не в осях драйвера и производных?

anonymous ()
Ответ на: комментарий от anonymous

Человеческие это с началом координат в нижнем левом углу? Но ведь по сути одинаково получается, что в верхнем лево, что в нижнем левом, не? Человек же вообще с координатами не работает, ну будет он видеть в статусбаре скажем: X:100 Y:200 Ему это всё равно ничего не скажет, хотя если даже и скажет, то думаю он быстро поймёт, что Y откладывается вниз, а не вверх... Просто с верх. лев. углом имхо проще )

xterro ★★★★★ ()
Ответ на: комментарий от xterro

ТЫ, похоже, никогда не чертил. А вот открой-ка QCad, да нарисуй что-нибудь, используя абсолютные и относительные координаты!

Anon ()
Ответ на: комментарий от Anon

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

anonymous ()
Ответ на: комментарий от Anon

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

xterro ★★★★★ ()
Ответ на: комментарий от xterro

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

anonymous ()
Ответ на: комментарий от anonymous

Вру конечно, можно и оформить и показать, но это лишняя работа пользователя, а делая ПО надо всегда помнить, что пользователь ленив. Заставлять его рвать себе шаблон, и делать бесполезную для него работу, плохая затея.

anonymous ()
Ответ на: комментарий от anonymous

++

С этого и надо начинать.

xterro

Т.е мне надо перед рисованием установить начало системы координат в нижнем левом углу, и рисовать/отображать всё в этой системе?

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

Anon ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.