Рассчитать вектор от точки в прямоугольнике до края на основе угла - PullRequest
2 голосов
/ 05 июля 2010

По словам Даниэля, в его ответе нет простого способа изменить приведенную ниже функцию, поэтому я укусил пулю и начал с нуля.Решение ниже (как ответ).На самом деле, игнорируйте мой ответ.Смотри, ответ Тома Сиргедаса намного короче.


Мне нужно изменить решение, найденное здесь: Рассчитать вектор от центра квадрата до края на основе радиуса , который вычисляет вектор из центра прямоугольника,работать для любой точки внутри прямоугольника.

Вот предыдущее решение по ссылке:

    double magnitude;
    double abs_cos_angle= fabs(cos(angle));
    double abs_sin_angle= fabs(sin(angle));
    if (width/2*abs_sin_angle <= height/2*abs_cos_angle)
    {
            magnitude= width/2/abs_cos_angle;
    }
    else
    {
            magnitude= height/2/abs_sin_angle;
    }

    double check_x= x + cos(angle)*magnitude;
    double check_y= y + sin(angle)*magnitude;

check_x и check_y возвращают точку на краю прямоугольника, из которой нарисована линияцентр под углом будет пересекаться.

Прошло много времени с тех пор, как я пошел в школу, поэтому я слепо пытался заменить width / 2 и height / 2 на интересующую меня точку. К сожалению, это не сработало.

ЛюбойИдеи?

ETA:

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

Ответы [ 5 ]

4 голосов
/ 07 июля 2010

Скажем, прямоугольник определен как (x1, y1, x2, y2), и допустим, что луч начинается с (px, py).

Пусть vx = cos (angle)

Пусть vy = sin (угол)

Пройдя расстояние t вдоль луча, вы попадете в точку (px + t vx, py + t vy).

Путешествуя по лучу,

  • мы попадаем в левую стену, когда px + t * vx = x1, или t = (x1-px) / vx
  • мы попадаем вправостена, когда px + t * vx = x2, или t = (x2-px) / vx
  • , мы попадаем на верхнюю стену, когда py + t * vy = y1 или t = (y1-py) / vy
  • мы попадаем в нижнюю стенку, когда py + t * vy = y2 или t = (y2-py) / vy

Итак, есть четыре возможных решения для t.Правильное значение t (среди четырех) является наименьшим положительным единичным.Фактическое пересечение находится в точке (px + t vx, py + t vy).Только будьте осторожны, чтобы не делить на ноль!

1 голос
/ 05 июля 2010

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

0 голосов
/ 06 июля 2010

Вы в основном запрашиваете полярное уравнение прямоугольника, и оно равно

r(t) = min(R, w*abs(sec(t)), h*abs(csc(t))); t = [0, 2pi]

, где w и h - полуширина и половина высоты, а R - любое число, большее или равноедо sqrt (ш ^ 2 + ч ^ 2).Это предполагает, что прямоугольник находится в начале координат, и если это не так, все, что вам нужно сделать, это добавить координаты центра к результату, который вы получите с помощью (r cos (t), r sin (t).)).Конечно, этот подход неприятен, так как у sec и csc есть особенности, но вы можете ограничить их до max (w, h).

0 голосов
/ 05 июля 2010

Приведенное ниже решение создает формулу для линии, которая проходит через указанную точку и пересекает границу прямоугольника под указанным углом.В зависимости от угла я проверяю, пересекается ли он с одной из двух границ прямоугольника.Я всегда основываю чек под углом от 0 до 90 градусов.Чтобы учесть это, тест в квадрантах Q2 и Q4 использует линию, которая перпендикулярна линии в Q1 и Q4.

Когда угол = 0, линия указывает на восток.
Я вычелугол от 360, так что линия вращается по часовой стрелке, а не против часовой стрелки.

Private Function GetIntersectionPoint(ByVal rectangleSize As SizeF, ByVal p As Point, ByVal degreeAngle As Single) As PointF

    Dim w = CInt(rectangleSize.Width)
    Dim h = CInt(rectangleSize.Height)
    degreeAngle = ((360 - degreeAngle) Mod 360)

    If degreeAngle = 0 Then
        Return New Point(w, p.Y)
    ElseIf degreeAngle = 90 Then
        Return New Point(p.X, 0)
    ElseIf degreeAngle = 180 Then
        Return New Point(0, p.Y)
    ElseIf degreeAngle = 270 Then
        Return New Point(p.X, h)
    End If

    Dim x, y As Integer

    If (degreeAngle > 0 AndAlso degreeAngle < 90) Then
        y = YFromX(degreeAngle, w, p)
        If y <= 0 AndAlso y >= -h Then
            Return New Point(w, -y)
        End If
        x = XFromY(degreeAngle, 0, p)
        Return New Point(x, 0)
    End If

    If (degreeAngle > 90 AndAlso degreeAngle < 180) Then
        degreeAngle -= 90
        y = YFromX_Perpedicular(degreeAngle, 0, p)
        If y <= 0 AndAlso y >= -h Then
            Return New Point(0, -y)
        End If
        x = XFromY_Perpendicular(degreeAngle, 0, p)
        Return New Point(x, 0)
    End If

    If (degreeAngle > 180 AndAlso degreeAngle < 270) Then
        degreeAngle -= 180
        y = YFromX(degreeAngle, 0, p)
        If y <= 0 AndAlso y >= -h Then
            Return New Point(0, -y)
        End If
        x = XFromY(degreeAngle, -h, p)
        Return New Point(x, h)
    End If

    If (degreeAngle > 270 AndAlso degreeAngle < 360) Then
        degreeAngle -= 270
        y = YFromX_Perpedicular(degreeAngle, w, p)
        If y <= 0 AndAlso y >= -h Then
            Return New Point(w, -y)
        End If
        x = XFromY_Perpendicular(degreeAngle, -h, p)
        Return New Point(x, h)
    End If

End Function

Private Function YFromX(ByVal degreeAngle As Single, ByVal x As Integer, ByVal p As Point) As Integer
    Dim alpha As Double = degreeAngle * Math.PI / 180
    Dim sinAlpha = Sin(alpha)
    Dim cosAlpha = Cos(alpha)
    Return CInt(sinAlpha / cosAlpha * (x - p.X) - p.Y)
End Function

Private Function XFromY(ByVal degreeAngle As Single, ByVal y As Integer, ByVal p As Point) As Integer
    Dim alpha As Double = degreeAngle * Math.PI / 180
    Dim sinAlpha = Sin(alpha)
    Dim cosAlpha = Cos(alpha)
    Return CInt(cosAlpha / sinAlpha * (y + p.Y) + p.X)
End Function

Private Function YFromX_Perpedicular(ByVal degreeAngle As Single, ByVal x As Integer, ByVal p As Point) As Integer
    Dim alpha As Double = degreeAngle * Math.PI / 180
    Dim sinAlpha = Sin(alpha)
    Dim cosAlpha = Cos(alpha)
    Return CInt((cosAlpha / sinAlpha) * (p.X - x) - p.Y)
End Function

Private Function XFromY_Perpendicular(ByVal degreeAngle As Single, ByVal y As Integer, ByVal p As Point) As Integer
    Dim alpha As Double = degreeAngle * Math.PI / 180
    Dim sinAlpha = Sin(alpha)
    Dim cosAlpha = Cos(alpha)
    Return CInt(p.X - sinAlpha / cosAlpha * (y + p.Y))
End Function
0 голосов
/ 05 июля 2010

Давайте сразу проясним одну вещь: мне кажется, что вы беспокоитесь о векторах в 2D. Все ваши очки находятся в плоскости. Также верно, что интересует именно этот прямоугольник (четыре угла, все с углами 90 градусов, две пары противоположных сторон имеют одинаковую длину)?

Центр вашего прямоугольника определяется как среднее значение четырех угловых точек:

альтернативный текст http://www.equationsheet.com/latexrender/pictures/ccdca519c24bb6ab2b6164144645572a.gif

альтернативный текст http://www.equationsheet.com/latexrender/pictures/84550340ace7dade26dc3294fef8e156.gif

Это отправная точка вашего вектора.

Любой вектор определяется двумя точками, поэтому вам просто нужна вторая точка (например, середина ребра) для вычисления вектора в 2D-пространстве:

альтернативный текст http://www.equationsheet.com/latexrender/pictures/7c680a2354f4a2a0d05d6c97ba949bc4.gif

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

...