Как обрезать отрезок линии относительно усеченного конуса?

Даны два вектора A и B, которые образуют отрезок L = AB. Кроме того, дан усеченный вид F, который определяется его левой, правой, нижней, верхней, ближней и дальней плоскостями.

Как привязать L к F?

То есть проверить наличие пересечения и, где на L происходит это пересечение? (Имейте в виду, что отрезок может иметь несколько пересечений с усеченной пирамидой, если он пересекает две стороны в углу.)

Если возможно, приведите пример кода (желательно C++ или Python).


person MHOOO    schedule 16.09.2008    source источник
comment
Я что-то упустил или вы могли бы просто пересечь L со всеми плоскостями? Что вообще такое усеченный? :)   -  person Sarien    schedule 17.09.2008
comment
Ах, я вижу, что у него есть передняя и задняя плоскости, но они неявные.   -  person Sarien    schedule 17.09.2008
comment
Почему мы должны делать домашнее задание за этого ребенка?   -  person Danimal    schedule 17.09.2008
comment
Это уже помечено как домашнее задание, если оно вам не нравится, проголосуйте против. Я не вижу причин для того, что я считаю непристойным тегированием.   -  person zxcv    schedule 17.09.2008


Ответы (3)


Я не хочу сейчас писать код для этого, но если я правильно понимаю «усеченную пирамиду», то должно работать следующее.

  1. Пересечь линию со всеми заданными плоскостями
  2. Если у вас есть два пересечения, все готово.
  3. Если у вас есть только одно пересечение, вычислите переднюю плоскость и пересечение.
  4. Если у вас все еще есть только одно пересечение, вычислите заднюю плоскость и пересечение.

Но я, возможно, совершенно неправильно понял. В таком случае, пожалуйста, уточните :)

person Sarien    schedule 16.09.2008
comment
Хм. На самом деле я хочу, чтобы сегмент линии не находился за пределами усеченной пирамиды видимости. Итак, если у меня есть два пересечения, я должен переместить и A, и B, чтобы они соответствовали пересекающимся границам. Увы, я понятия не имею, как это работает. - person MHOOO; 17.09.2008

Вдобавок к тому, что выше сказал капрал Недотрога, вам нужно знать, как пересекает отрезок прямой с плоскостью. В описании на этой странице u представляет параметр в параметрическом определении вашей линии. Сначала вычислите u, используя один из двух описанных методов. Если значение u попадает в диапазон от 0,0 до 1,0, то плоскость обрезает линию где-то на вашем сегменте. Подставив u обратно в ваше линейное уравнение, вы получите точку, в которой происходит это пересечение.

Другой подход заключается в нахождении направленного расстояния от каждой точки до плоскости. Если расстояние одной точки положительно, а другой отрицательно, то они лежат по разные стороны плоскости. Затем вы знаете, какая точка находится за пределами усеченного конуса (в зависимости от того, куда указывает нормаль вашей плоскости). Используя этот подход, можно быстрее найти точку пересечения, выполнив линейную интерполяцию на основе отношения направленных расстояний. Например. если расстояние до одной точки равно +12, а до другой -12, вы знаете, что плоскость делит отрезок пополам, и ваш параметр u равен 0,5.

Надеюсь это поможет.

person jasonmray    schedule 18.09.2008

Сначала извлеките плоскости из матрицы просмотра.

Затем используйте свои точки для определения вектора и минимума/максимума как (0, 1), затем перебирайте плоскости и пересекайте их с сегментом, обновляя минимум/максимум, выручая раньше, если min > max.

Вот пример чистой функции Python, без внешних зависимостей.

def clip_segment_v3_plane_n(p1, p2, planes):
    """
    - p1, p2: pair of 3d vectors defining a line segment.
    - planes: a sequence of (4 floats): `(x, y, z, d)`.

    Returns 2 vector triplets (the clipped segment)
    or (None, None) then segment is entirely outside.
    """
    dp = sub_v3v3(p2, p1)

    p1_fac = 0.0
    p2_fac = 1.0

    for p in planes:
        div = dot_v3v3(p, dp)
        if div != 0.0:
            t = -plane_point_side_v3(p, p1)
            if div > 0.0:  # clip p1 lower bounds
                if t >= div:
                    return None, None
                if t > 0.0:
                    fac = (t / div)
                    if fac > p1_fac:
                        p1_fac = fac
                        if p1_fac > p2_fac:
                            return None, None
            elif div < 0.0:  # clip p2 upper bounds
                if t > 0.0:
                    return None, None
                if t > div:
                    fac = (t / div)
                    if fac < p2_fac:
                        p2_fac = fac
                        if p1_fac > p2_fac:
                            return None, None

    p1_clip = add_v3v3(p1, mul_v3_fl(dp, p1_fac))
    p2_clip = add_v3v3(p1, mul_v3_fl(dp, p2_fac))

    return p1_clip, p2_clip


# inline math library
def add_v3v3(v0, v1):
    return (
        v0[0] + v1[0],
        v0[1] + v1[1],
        v0[2] + v1[2],
        )

def sub_v3v3(v0, v1):
    return (
        v0[0] - v1[0],
        v0[1] - v1[1],
        v0[2] - v1[2],
        )

def dot_v3v3(v0, v1):
    return (
        (v0[0] * v1[0]) +
        (v0[1] * v1[1]) +
        (v0[2] * v1[2])
        )

def mul_v3_fl(v0, f):
    return (
        v0[0] * f,
        v0[1] * f,
        v0[2] * f,
        )

def plane_point_side_v3(p, v):
    return dot_v3v3(p, v) + p[3]
person ideasman42    schedule 23.01.2016