Вместо того, чтобы отлаживать ваш код, я просто объясню, как мне это сделать.
Сначала несколько терминов.Давайте определим xRadius
как половину ширины рамки, а yRadius
как половину высоты рамки.
Теперь рассмотрим четыре края рамки и вытяните их как бесконечные линии.Поверх этих четырех линий положите линию, которая проходит через центр рамки под указанным вами углом:
Скажем, рамка находится по центру в начале координат - в центрекадра в координатах (0,0).Мы можем легко вычислить, где диагональная линия пересекает правый край рамки: координаты (xRadius
, xRadius * tan(angle)
).И мы можем легко вычислить, где диагональная линия пересекает верхний край фрейма: координаты (-yRadius / tan(angle)
, -yRadius
).
(Почему мы отрицаем координаты для пересечения верхнего края?Потому что система координат UIView
перевернута из обычной математической системы координат. В математике координаты y увеличиваются к верхней части страницы. В UIView
координаты y увеличиваются к нижней части вида.)
Таким образом, мы можем просто вычислить пересечение линии с правым краем кадра.Если это пересечение находится за пределами рамки, то мы знаем, что линия должна пересекать верхний край , прежде чем пересекает правый край.Как мы узнаем, что пересечение правого края выходит за границы?Если его координата y (xRadius * tan(angle)
) больше, чем yRadius
(или меньше, чем -yRadius
), это выходит за пределы.
Итак, чтобы сложить все вместе в методе, мы начнем с вычисления xRadius
и yRadius
:
- (CGPoint)radialIntersectionWithConstrainedRadians:(CGFloat)radians {
// This method requires 0 <= radians < 2 * π.
CGRect frame = self.frame;
CGFloat xRadius = frame.size.width / 2;
CGFloat yRadius = frame.size.height / 2;
Затем мы вычисляем координату y пересечения с правым краем:
CGPoint pointRelativeToCenter;
CGFloat tangent = tanf(radians);
CGFloat y = xRadius * tangent;
Проверяем, находится ли пересечение в кадре:
if (fabsf(y) <= yRadius) {
Как только мы узнаем, что это в кадре, мы должны выяснить, хотим ли мы пересечение с правым или левым краем.Если угол меньше π / 2 (90 °) или больше 3π / 2 (270 °), нам нужен правый край.В противном случае нам нужен левый край.
if (radians < (CGFloat)M_PI_2 || radians > (CGFloat)(M_PI + M_PI_2)) {
pointRelativeToCenter = CGPointMake(xRadius, y);
} else {
pointRelativeToCenter = CGPointMake(-xRadius, -y);
}
Если координата y пересечения правого края • была * вне пределов, мы вычисляем координату x пересечения с нижним краем.
} else {
CGFloat x = yRadius / tangent;
Затем мы выясним, хотим ли мы верхний край или нижний край.Если угол меньше π (180 °), нам нужен нижний край.В противном случае нам нужен верхний край.
if (radians < (CGFloat)M_PI) {
pointRelativeToCenter = CGPointMake(x, yRadius);
} else {
pointRelativeToCenter = CGPointMake(-x, -yRadius);
}
}
Наконец, мы смещаем вычисленную точку на фактический центр кадра и возвращаем ее.
return CGPointMake(pointRelativeToCenter.x + CGRectGetMidX(frame),
pointRelativeToCenter.y + CGRectGetMidY(frame));
}
Тестовый проект здесь: https://github.com/mayoff/stackoverflow-radial-intersection
выглядит так: