Поиск точек на прямоугольнике под заданным углом
Я пытаюсь нарисовать градиент в объекте прямоугольника с заданным углом (Theta), где концы градиента касаются периметра прямоугольника.
![Graph]()
Я думал, что использование касательной будет работать, но у меня возникают проблемы с получением перегибов. Есть ли простой алгоритм, который мне просто не хватает?
Конечный результат
Итак, это будет функция (угол, RectX1, RectX2, RectY1, RectY2). Я хочу, чтобы он возвращался в виде [x1, x2, y1, y2], так что градиент будет рисовать по квадрату.
В моей задаче, если начало координат равно 0, то x2 = -x1 и y2 = -y1. Но это не всегда будет происходить.
Ответы
Ответ 1
Позвольте называть a и b ваши стороны прямоугольника и (x0, y0) координаты вашего центра прямоугольника.
У вас есть четыре области:
![alt text]()
Region from to Where
====================================================================
1 -arctan(b/a) +arctan(b/a) Right green triangle
2 +arctan(b/a) π-arctan(b/a) Upper yellow triangle
3 π-arctan(b/a) π+arctan(b/a) Left green triangle
4 π+arctan(b/a) -arctan(b/a) Lower yellow triangle
С небольшим количеством тригонометрии-fu мы можем получить координаты для вашего желаемого пересечения в каждом регионе.
![alt text]()
So Z0 - выражение для точки пересечения для областей 1 и 3
И Z1 - выражение для точки пересечения для областей 2 и 4
Желательные линии проходят от (X0, Y0) до Z0 или Z1 в зависимости от региона. Так что помните, что Tan (& phi;) = Sin (& phi;)/Cos (& phi;)
Lines in regions Start End
======================================================================
1 and 3 (X0,Y0) (X0 + a/2 , (a/2 * Tan(φ))+ Y0
2 and 4 (X0,Y0) (X0 + b/(2* Tan(φ)) , b/2 + Y0)
Просто знайте знаки Tan (& phi;) в каждом квадранте и что угол всегда измеряется от ПОЛОЖИТЕЛЬНОЙ оси x ANTICLOCKWISE.
НТН!
Ответ 2
Хорошо, вот, я наконец получил этот.
ПРИМЕЧАНИЕ: Я основывал это на ответе на большой вопрос. Если вам это нравится, пожалуйста, как и его. Все, что я сделал, это превратить то, что он сказал в код.
Вот как это выглядит в Objective-C. Он должен быть достаточно простым, чтобы преобразовать его в ваш любимый язык.
+ (CGPoint) edgeOfView: (UIView*) view atAngle: (float) theta
{
// Move theta to range -M_PI .. M_PI
const double twoPI = M_PI * 2.;
while (theta < -M_PI)
{
theta += twoPI;
}
while (theta > M_PI)
{
theta -= twoPI;
}
// find edge ofview
// Ref: http://stackoverflow.com/questions/4061576/finding-points-on-a-rectangle-at-a-given-angle
float aa = view.bounds.size.width; // "a" in the diagram
float bb = view.bounds.size.height; // "b"
// Find our region (diagram)
float rectAtan = atan2f(bb, aa);
float tanTheta = tan(theta);
int region;
if ((theta > -rectAtan)
&& (theta <= rectAtan) )
{
region = 1;
}
else if ((theta > rectAtan)
&& (theta <= (M_PI - rectAtan)) )
{
region = 2;
}
else if ((theta > (M_PI - rectAtan))
|| (theta <= -(M_PI - rectAtan)) )
{
region = 3;
}
else
{
region = 4;
}
CGPoint edgePoint = view.center;
float xFactor = 1;
float yFactor = 1;
switch (region)
{
case 1: yFactor = -1; break;
case 2: yFactor = -1; break;
case 3: xFactor = -1; break;
case 4: xFactor = -1; break;
}
if ((region == 1)
|| (region == 3) )
{
edgePoint.x += xFactor * (aa / 2.); // "Z0"
edgePoint.y += yFactor * (aa / 2.) * tanTheta;
}
else // region 2 or 4
{
edgePoint.x += xFactor * (bb / (2. * tanTheta)); // "Z1"
edgePoint.y += yFactor * (bb / 2.);
}
return edgePoint;
}
Кроме того, здесь небольшой тестовый просмотр, который я создал, чтобы проверить, что он работает. Создайте это представление и поместите его где-нибудь, он сделает еще один небольшой просмотр вокруг края.
@interface DebugEdgeView()
{
int degrees;
UIView *dotView;
NSTimer *timer;
}
@end
@implementation DebugEdgeView
- (void) dealloc
{
[timer invalidate];
}
- (id) initWithFrame: (CGRect) frame
{
self = [super initWithFrame: frame];
if (self)
{
self.backgroundColor = [[UIColor magentaColor] colorWithAlphaComponent: 0.25];
degrees = 0;
self.clipsToBounds = NO;
// create subview dot
CGRect dotRect = CGRectMake(frame.size.width / 2., frame.size.height / 2., 20, 20);
dotView = [[DotView alloc] initWithFrame: dotRect];
dotView.backgroundColor = [UIColor magentaColor];
[self addSubview: dotView];
// move it around our edges
timer = [NSTimer scheduledTimerWithTimeInterval: (5. / 360.)
target: self
selector: @selector(timerFired:)
userInfo: nil
repeats: YES];
}
return self;
}
- (void) timerFired: (NSTimer*) timer
{
float radians = ++degrees * M_PI / 180.;
if (degrees > 360)
{
degrees -= 360;
}
dispatch_async(dispatch_get_main_queue(), ^{
CGPoint edgePoint = [MFUtils edgeOfView: self atAngle: radians];
edgePoint.x += (self.bounds.size.width / 2.) - self.center.x;
edgePoint.y += (self.bounds.size.height / 2.) - self.center.y;
dotView.center = edgePoint;
});
}
@end
Ответ 3
Версия Javascript:
function edgeOfView(rect, deg) {
var twoPI = Math.PI*2;
var theta = deg * Math.PI / 180;
while (theta < -Math.PI) {
theta += twoPI;
}
while (theta > Math.PI) {
theta -= twoPI;
}
var rectAtan = Math.atan2(rect.height, rect.width);
var tanTheta = Math.tan(theta);
var region;
if ((theta > -rectAtan) && (theta <= rectAtan)) {
region = 1;
} else if ((theta > rectAtan) && (theta <= (Math.PI - rectAtan))) {
region = 2;
} else if ((theta > (Math.PI - rectAtan)) || (theta <= -(Math.PI - rectAtan))) {
region = 3;
} else {
region = 4;
}
var edgePoint = {x: rect.width/2, y: rect.height/2};
var xFactor = 1;
var yFactor = 1;
switch (region) {
case 1: yFactor = -1; break;
case 2: yFactor = -1; break;
case 3: xFactor = -1; break;
case 4: xFactor = -1; break;
}
if ((region === 1) || (region === 3)) {
edgePoint.x += xFactor * (rect.width / 2.); // "Z0"
edgePoint.y += yFactor * (rect.width / 2.) * tanTheta;
} else {
edgePoint.x += xFactor * (rect.height / (2. * tanTheta)); // "Z1"
edgePoint.y += yFactor * (rect.height / 2.);
}
return edgePoint;
};
Ответ 4
Следуя вашей картине, я собираюсь предположить, что прямоугольник центрирован на (0,0), а верхний правый угол (w, h). Тогда линия, соединяющая (0,0) с (w, h), образует угол & phi; с осью X, где tan (& phi;) = h/w.
Предполагая, что & theta; > </phi;, мы ищем точку (x, y), где линия, которую вы нарисовали, пересекает верхний край прямоугольника. Тогда y/x = tan (& theta;). Мы знаем, что y = h, поэтому, решая для x, получаем x = h/tan (& theta;).
Если & theta; < Линия пересекается с правым краем прямоугольника в точке (x, y). На этот раз мы знаем, что x = w, поэтому y = tan (& theta;) * w.
Ответ 5
Здесь хороший (более программный iOS/ Objective-C) ответ на этот вопрос в Найдите CGPoint на прямоугольнике UIView, пересекаемом прямой линией под заданным углом от центральной точки с использованием следующих шагов:
- Предположим, что угол больше или равен 0 и меньше 2 * π, идущий против часовой стрелки от 0 (Восток).
- Получить координату y пересечения с правым краем прямоугольника [tan (angle) * width/2].
- Убедитесь, что эта координата y находится в рамке прямоугольника (абсолютное значение меньше или равно половине высоты).
- Если пересечение y находится в прямоугольнике, то, если угол меньше π/2 или больше 3π/2, выберите правый край (ширина/2, -y координата). В противном случае выберите левый край (-width/2, y coord).
- Если координата y пересечения правого края была вне пределов, вычислите координату x пересечения с нижним краем [половина высоты /tan (угол)].
- Далее определите, хотите ли вы верхний край или нижний край. Если угол меньше π, нам нужен нижний край (x, -half height). В противном случае нам нужен верхний край (-x координата, половина высоты).
- Затем (если центр кадра не равен 0,0), смещайте точку на фактический центр кадра.