2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




Начать новую тему Ответить на тему
 
 Рамка на координатной сетке
Сообщение17.08.2020, 15:11 


21/05/16
4292
Аделаида
Пусть есть бесконечная координатная сетка (для определенности, с шагом 2). Также есть некая рамка (просто прямоугольник шириной в $1$ и высотой в $\frac12$) с центром где-то на плоскости (мы знаем координаты центра, они нецелы). Квадраты координатной сетки заполнены какими-то изображениями (один квадрат - одно изображение, заполняющее его целиком, без перекрытий и наложений). Надо заполнить рамку соответствующими фрагментами изображений (рамка показывается пользователю). Рамка заполняется через функции https://developer.mozilla.org/en-US/doc ... gContext2D (это тут не слишком принципально, можно использовать эту ссылку просто как список аргументов функцци).
Для иллюстрации:
Изображение
Большие черные квадраты - квадраты сетки. Черные прямоугольники - рамки. Черные точки внутри рамок - их центры (на рисунке я нарисовал их не очень центральными, правда...). Красная и желтая линии - координаты центра (относительно угла соответствущего квадрата). Синие и зеленые линии ограничивают области точек, где ситуация существенно меняется (в зеленом прямоугольнике - только один фрагмент изображения получается, в зелено-сине-черных - два, сине-черных - четыре).

Есть ли возможность это сделать проще, чем простым перебором if'ами, в каком из синих/зеленых/черных прямоугольников находится центр (тогда получается пара сотен строк примерно такого кода:
код: [ скачать ] [ спрятать ]
Используется синтаксис Javascript
if ((remainderCoordinates[0] >= canvasSize[0] / 2) && (remainderCoordinates[0] <= backgroundSize - canvasSize[0] / 2) &&
          (remainderCoordinates[1] >= canvasSize[1] / 2) && (remainderCoordinates[1] <= backgroundSize - canvasSize[1] / 2)) {
                try {
                        let img = await getBackground(divisionCoordinates[0], divisionCoordinates[1]);
                        let sx = remainderInPixels[0] - canvas.width / 2;
                        let sy = backgroundSize * coordinateInPixels - remainderInPixels[1] - canvas.height / 2;
                        let width = canvas.width;
                        let height = canvas.height;
                        let dx = 0;
                        let dy = 0;
                        context.drawImage(img, sx, sy, width, height, dx, dy, width, height);
                } catch {};
        } else if ((remainderCoordinates[1] >= canvasSize[1] / 2) &&
          (remainderCoordinates[1] <= backgroundSize - canvasSize[1] / 2)) {
                let sx1 = (remainderInPixels[0] - canvas.width / 2) % (backgroundSize * coordinateInPixels);
                let sy1 = backgroundSize * coordinateInPixels - remainderInPixels[1] - canvas.height / 2;
                let width1 = backgroundSize * coordinateInPixels - sx1;
                let height1 = canvas.height;
                let dy1 = 0;
                try {
                        let image1 = await getBackground(divisionCoordinates[0] - (remainderCoordinates[0] <= canvasSize[0] / 2),
                      divisionCoordinates[1]);
                        let dx1 = 0;
                        context.drawImage(image1, sx1, sy1, width1, height1, dx1, dy1, width1, height1);
                } catch {};
                try {
                        let image2 = await getBackground(divisionCoordinates[0] + (remainderCoordinates[0] >= canvasSize[0] / 2),
                          divisionCoordinates[1]);
                        let sx2 = 0;
                        let sy2 = sy1;
                        let width2 = canvas.width - width1;
                        let height2 = height1;
                        let dx2 = width1;
                        let dy2 = dy1;
                        context.drawImage(image2, sx2, sy2, width2, height2, dx2, dy2, width2, height2);
                } catch {};
        } else if ((remainderCoordinates[0] >= canvasSize[0] / 2) &&
          (remainderCoordinates[0] <= backgroundSize - canvasSize[0] / 2)) {
                let sx1 = remainderInPixels[0] - canvas.width / 2;
                let sy1 = (-canvas.height / 2 - remainderInPixels[1] * (remainderCoordinates[1] <= canvasSize[1] / 2 ? 1 : -1)) %
                  (backgroundSize * coordinateInPixels);
                let width1 = canvas.width;
                let height1 = backgroundSize * coordinateInPixels - sy1;
                let dx1 = 0;
                try {
                        let image1 = await getBackground(divisionCoordinates[0], divisionCoordinates[1] +
                          (remainderCoordinates[1] >= backgroundSize - canvasSize[1] / 2));
                        let dy1 = 0;
                        context.drawImage(image1, sx1, sy1, width1, height1, dx1, dy1, width1, height1);
                } catch {};
                try {
                        let image2 = await getBackground(divisionCoordinates[0], divisionCoordinates[1] -
                          (remainderCoordinates[1] <= canvasSize[1] / 2));
                        let sx2 = sx1;
                        let sy2 = 0;
                        let width2 = width1;
                        let height2 = canvas.height - height1;
                        let dx2 = dx1;
                        let dy2 = height1;
                        context.drawImage(image2, sx2, sy2, width2, height2, dx2, dy2, width2, height2);
                } catch {};
      } перебор остальных вариантов

(remainderCoordinates[0] и [1] - длина красной и желтой линий в координатах, canvasSize - размер рамки в координатах, backgroundSize - размер квадратов сетки в координатах, coordinateInPixels, remainderInPixels, и canvas.width/height - размеры координаты, красной и желтой линий, а так же размеры рамки в пикселях, это не так важно))?

 Профиль  
                  
 
 Re: Рамка на координатной сетке
Сообщение17.08.2020, 19:57 
Заслуженный участник


20/08/14
11760
Россия, Москва
Посмотрите оптимизацию отсечения невидимых линий в компьютерной графике (я помню про методы разбиения пространства), кажется это 1-в-1 та задача, решённая ещё при появлении первых версий графической оболочки (и уж точно не позже первых многозадачных Windows). Вариантов решения может быть больше одного, смотря сколько рамок и сколько объектов всего в сцене, какое соотношение размеров рамки и клеток, кучкования объектов в клетках и т.д.
Ну и полный перебор вроде бы не обязателен, можно поделить объекты на списки для каждой клетки и по координатам центра рамки перебирать лишь максимум 4 клеток (если размер рамки не больше размера клетки). Если клеток сильно больше десятка, то это выгодно.
Ну и зачем кучи if-ов не совсем ясно, можно же сложить объекты в массив по клеткам и получать номер клетки из координат рамки просто делением с округлением двух чисел.
Или я опять не вник в смысл задачи. :-(

 Профиль  
                  
 
 Re: Рамка на координатной сетке
Сообщение17.08.2020, 20:03 


21/05/16
4292
Аделаида
Вы не поняли, похоже... Координаты легко получаются, это и есть красная и желтая линии. If'ы служат для различия девяти принципиально разных ситуаций.

 Профиль  
                  
 
 Re: Рамка на координатной сетке
Сообщение17.08.2020, 20:21 
Заслуженный участник
Аватара пользователя


16/07/14
9143
Цюрих
Я бы предложил для каждого из углов прямоугольника скопировать тот кусок, который в него попадает. При желании можно оптимизировать - обходим углы в фиксированном порядке, и очередной берем, если он не попал в тот же квадрат, что один из предыдущих.

 Профиль  
                  
 
 Re: Рамка на координатной сетке
Сообщение17.08.2020, 20:27 
Аватара пользователя


11/12/16
13848
уездный город Н
Dmitriy40
Насколько понял, ТС нужно узнать в какой из 9 областей клетки оказался центр рамки, что выбрать правильный способ заполнения рамки (из одной, двух или четырех картинок).

kotenok gav
9 областей формируются тремя полосами по вертикали и тремя по горизонтали.

1. Делая всего два сравнения, Вы получаете номер полосы по вертикали, $i$.
2. Делая точно так же еще два сравнения, Вы получаете номер полосы по вертикали, $j$.
3. Считаете $k = i +3(j-1)$, получаете номер области внутри клетки, от 1 до 9. Вот Вам девять отличающихся вариантов.

Если внимательно на них посмотреть, то принципиально различающися там 3 типа:
1. Номер $5$ - нет соседей.
2. Нечетные номера, кроме $5$ - четыре соседа.
3. Четные номера - два соседа.

Можно даже такую нумерацию ввести, что она сразу даст количество соседей.

 Профиль  
                  
 
 Re: Рамка на координатной сетке
Сообщение17.08.2020, 20:40 


21/05/16
4292
Аделаида
EUgeneUS в сообщении #1479626 писал(а):
Насколько понял, ТС нужно узнать в какой из 9 областей клетки оказался центр рамки, что выбрать правильный способ заполнения рамки (из одной, двух или четырех картинок).

Нет. Это-то как раз и делается if'ами. Просто каждый способ заполнения весьма длинн, и поэтому я не хочу повторять его несколько раз по всем if'ам.
mihaild в сообщении #1479625 писал(а):
Я бы предложил для каждого из углов прямоугольника скопировать тот кусок, который в него попадает. При желании можно оптимизировать - обходим углы в фиксированном порядке, и очередной берем, если он не попал в тот же квадрат, что один из предыдущих.

Не совсем понял... Можно пример?

 Профиль  
                  
 
 Re: Рамка на координатной сетке
Сообщение17.08.2020, 20:57 
Заслуженный участник
Аватара пользователя


16/07/14
9143
Цюрих
Проще всего как-то так: делаем из координат центра список координат левых нижних углов прямоугольников, целиком лежащих в одной ячейке, которые нам надо скопировать:
код: [ скачать ] [ спрятать ]
Используется синтаксис C++
int round_to_smaller(float x); // округляет вниз до кратного 2
vector<pair<float, float>> get_corners(float xc, float yc) {
  vector<pair<float, float>> result;
  float x0  = xc - 0.5, x1 = xc + 0.5, y0 = yc - 0.25, y1 = yc + 0.25;
  result.emplace_back(x0, y0);
  if (round_to_smaller(x0) != round_to_smaller(x1)) {
    result.emplace_back(round_to_smaller(x1), y0);
  }
  if (round_to_smaller(y0) != round_to_smaller(y1)) {
    result.emplace_back(x0, round_to_smaller(y1));
  }
  if (round_to_smaller(x0) != round_to_smaller(x1) && round_to_smaller(y0) != round_to_smaller(y1)) {
    result.emplace_back(round_to_smaller(x0), round_to_smaller(y1));
  }
  return result;
}
 

Дальше для каждого из углов копируем нужный кусок картинки:
Используется синтаксис C++
void copy_part(float x0, float y0, float x1, float y1); // копирует прямоугольник с плоскости с углами (x0, y0) и (x1, y1) в нашу рамку; нужно, чтобы этот прямоугольник лежал в одной клетке и накрывался рамкой
void fill_image(float xc, float yc) {
  auto corners = get_corners(xc, yc);
  float x1 = xc + 0.5, y1 = yc + 0.25;
  for (auto [x, y] : corners) {
    copy_part(x, y, min(x1, round_to_smaller(x) + 2), min(y1, round_to_smaller(y) + 2);
  }
}
 

 Профиль  
                  
 
 Re: Рамка на координатной сетке
Сообщение17.08.2020, 21:24 


21/05/16
4292
Аделаида
mihaild, спасибо! Кажется, так получится...

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 8 ] 

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group