По заданному углу и размерам найти координату по периметру прямоугольника.
-
06-07-2019 - |
Вопрос
Я пишу сценарий, в котором значки вращаются вокруг заданной точки поворота (или начала координат).Мне удалось добиться вращения значков вокруг эллипса, но я также хочу, чтобы они перемещались по периметру прямоугольника определенной ширины, высоты и начала координат.
Я делаю это таким образом, потому что мой текущий код хранит все координаты в массиве, где каждое целое число угла является ключом, и с повторным использованием этого кода будет намного проще работать.
Если бы кто-нибудь мог дать мне пример прямоугольника 100x150, это было бы здорово.
РЕДАКТИРОВАТЬ: Чтобы уточнить, под вращением я подразумеваю перемещение по периметру (или вращению по орбите) фигуры.
Решение
Вы знаете размер прямоугольника, и вам нужно разделить весь интервал углов на четыре разных, чтобы знать, пересекает ли луч из центра прямоугольника правую, верхнюю, левую или нижнюю часть прямоугольника.
Если угол:-atan(d/w) < alfa < atan(d/w) луч пересекает правую сторону прямоугольника.Тогда, поскольку вы знаете, что смещение по оси x от центра прямоугольника к правой стороне равно d/2, смещение dy, деленное на d/2, равно tan(alfa), поэтому
dy = d/2 * tan(альфа)
Вы поступили бы так же, как и с другими тремя угловыми интервалами.
Хорошо, вот и все.У вас есть прямоугольник шириной w и глубиной d.В середине у вас есть центральная точка, cp.Я предполагаю, что вы хотите вычислить P для разных значений угла альфа.
Я разделил прямоугольник на четыре разные области или угловые интервалы (от 1 до 4).Упомянутый выше интервал — первый справа.Надеюсь, это имеет для вас смысл.
Сначала нужно рассчитать интервалы углов, они полностью определяются w и d. В зависимости от того, какое значение имеет альфа, соответственно вычисляют P, т.е.если «луч» от CP до P пересекает верхнюю, нижнюю, правую или левую стороны прямоугольника.
Ваше здоровье
Другие советы
Это было сделано и проверено для работы с умными часами Pebble, но изменено на псевдокод:
struct GPoint {
int x;
int y;
}
// Return point on rectangle edge. Rectangle is centered on (0,0) and has a width of w and height of h
GPoint getPointOnRect(int angle, int w, int h) {
var sine = sin(angle), cosine = cos(angle); // Calculate once and store, to make quicker and cleaner
var dy = sin>0 ? h/2 : h/-2; // Distance to top or bottom edge (from center)
var dx = cos>0 ? w/2 : w/-2; // Distance to left or right edge (from center)
if(abs(dx*sine) < abs(dy*cosine)) { // if (distance to vertical line) < (distance to horizontal line)
dy = (dx * sine) / cosine; // calculate distance to vertical line
} else { // else: (distance to top or bottom edge) < (distance to left or right edge)
dx = (dy * cosine) / sine; // move to top or bottom line
}
return GPoint(dx, dy); // Return point on rectangle edge
}
Use:
rectangle_width = 100;
rectangle_height = 150;
rectangle_center_x = 300;
rectangle_center_y = 300;
draw_rect(rectangle_center_x - (rectangle_width/2), rectangle_center_y - (rectangle_center_h/2), rectangle_width, rectangle_height);
GPoint point = getPointOnRect(angle, rectangle_width, rectangle_height);
point.x += rectangle_center_x;
point.y += rectangle_center_y;
draw_line(rectangle_center_x, rectangle_center_y, point.x, point.y);
Один простой способ сделать это, используя угол в качестве параметра, - просто обрезать значения X и Y, используя границы прямоугольника. Другими словами, рассчитайте положение, как если бы значок вращался вокруг круговой или эллиптической траектории, а затем примените это:
(Предполагается, что выровненный по оси прямоугольник с центром в (0,0), с длиной оси X для оси X и длиной оси Y для оси Y):
if (X > XAxis/2)
X = XAxis/2;
if (X < 0 - XAxis/2)
X = 0 - XAxis/2;
if (Y > YAxis/2)
Y = YAxis/2;
if (Y < 0 - YAxis/2)
Y = 0 - YAxis/2;
Проблема этого подхода заключается в том, что угол не будет полностью точным, а скорость по периметру прямоугольника не будет постоянной. Моделирование эллипса, который изгибает прямоугольник в его углах, может минимизировать эффект, но если вы ищете плавную & Quot; orbit, & Quot; этот метод не будет адекватным.
Если вы думаете, что имеете в виду вращение, как вращение Земли вокруг Солнца (не самовращение ... так что ваш вопрос о том, как скользить по краям прямоугольника?)
Если это так, вы можете попробовать это.
# pseudo coode
for i = 0 to 499
if i < 100: x++
else if i < 250: y--
else if i < 350: x--
else y++
drawTheIcon(x, y)
Обновление: (см. комментарий ниже)
для использования угла одна строка будет
y / x = tan(th) # th is the angle
остальные строки просты, так как они просто горизонтальные или вертикальные. так, например, это х = 50, и вы можете поместить это в строку выше, чтобы получить у. сделать это для пересечения горизонтальной линии и вертикальной линии (например, угол равен 60 градусам, и он стреляет " NorthEast " ... теперь у вас есть две точки. Затем точка, ближайшая к источник - это тот, который первым попадает в прямоугольник).
Используйте матрицу 2D-преобразования . Многие языки (например, Java) поддерживают это изначально (ищите AffineTransformation); в противном случае, запишите процедуру, чтобы сделать ротацию самостоятельно, один раз, отладить ее и использовать ее навсегда. У меня должно быть пять из них написаны на разных языках.
Как только вы сможете просто выполнить вращение, найдите местоположение в прямоугольнике, выполнив line-line пересечение . Найдите центр орбитальной иконки, пересекая две линии:
<Ол>Нарисуйте эскиз на листе бумаги с прямоугольником и центром вращения. Сначала переведите прямоугольник в центр в начале координат вашей системы координат (запомните параметры перевода, вам нужно будет перевернуть перевод позже). Поверните прямоугольник так, чтобы его стороны были параллельны осям координат (по той же причине).
Теперь у вас есть треугольник с известным углом в начале координат, противоположная сторона имеет известную длину (половину длины одной стороны прямоугольника), и теперь вы можете:
- решить треугольник
- отменить вращение
- отменить перевод