1
votes

I have two planes P1 and P2 specified as normal-distance, or 4D vectors. I also have a parameter t. I need to construct a derived plane P which is coincident with P1 for t = 0, coincident with P2 for t = 1, and in-between for t = (0, 1). In the end P should also be represented as a 4D-vector.

Intuitively P should be constructed such that P1, P2 and P intersect at the same line, and the angle P1∠P = (P1∠P2)t.

Is there an efficient math for this? Can this be solved precisely?

Clarification

Linear interpolation of the angle between planes is actually a requirement. In other words the normal NP must linearly rotate between NP1 and NP2 through the shortest arc.

2
The straight-forward way to code these requirements would be: Calculate the intersection line. Then interpolate the rotation about that line. - Nico Schertler

2 Answers

0
votes

Here is a nice strategy that utilizes the vector slerp function for the interpolated plane normal and any point on the common line of the two planes.

Start with the definition of each plane, having normal vectors n_1 = (nx_1,ny_1,nz_1), n_2 = (nx_2,ny_2,nz_2) and distance from origin (measured in the direction of the normal) as d_1 and d_2.

The common line of the two planes is along the (non-unit) direction e = cross(n_1, n_2). The point on this line closest to the origin is given by the calculation

point = (d_2*cross(n_1,e)-d_1*cross(n_2,e))/dot(e,e)

Notation is in pseudo-code with elements from most common languages

Keep this to the side for now, and focus on interpolating the normals. I you use a n = slerp(n_1, n_2, t) function it will interpolate along the minimum arc and have equal spacings

vector slerp(vector n_1, vector n_2, float t)
    // Assume n_1, n_2 are unit vectors
    // Result is always a unit vector
    float g = dot(n_1, n_2)
    float angle = acos(g)
    float f = sin(angle)
    return (sin((1-t)*angle)/f)*n_1 + (sin(t*angle)/f)*n_2
end

So now we can define the interpolated plane using the normal n = slerp(n_1, n_2, t) and the distance d = dot(n, point) from the projection of the common point to along the new normal.

The algorithm below extends the slerp function to work with planes also:

plane slerp(plane p_1, plane p_2, float t)
    // extract properties from plane
    vector n_1 = p_1.normal, n_2 = p_2.normal
    float d_1 = p_1.distance, d_2 = p_2.distance       
    // interpolate
    vector e = cross(n_1, n_2))
    vector n = slerp(n_1, n_2, t)
    vector r = (d_2*cross(n_1,e)-d_1*cross(n_2,e))/dot(e,e)
    // construct new plane from normal and distance
    return plane(n, dot(r, n))
 end

Some helper functions as expected:

float dot(vector a, vector b)
    return a.x*b.x + a.y*b.y + a.z*b.z
end

float hypot(vector a) 
    return sqrt(dot(a,a))
end

vector cross(vector a, vector b) 
    return vector( a.y*b.z-a.z*b.y, a.z*b.x-a.x*b.z, a.x*b.y-a.y*b.x)
end

vector operator * (float f, vector a)
    return vector(f*a.x, f*a.y, f*a.z)
end

vector operator + (vector a, vector b)
    return vector(a.x+b.x, a.y+b.y, a.z+b.z)
end
-1
votes

I don't know about efficient in terms of computing time, but it can definitely be solved.

enter image description here

(Imagine a P_t (your P) just beside c_t. a, a_t, b, and c_t are angles.)

In the terms of this illustration, you want a_t = a * t, t in (0, 1).

We want to find l_t in terms of t, and importantly l_t is not simply t * ||P_3||.

Firstly, cos(a) = P1 * P2 / (||P1|| * ||P2||), where * is the standard vector dot product if between vectors and otherwise the standard scalar multiplication.

Then a = arccos(P1 * P2 / (||P1|| * ||P2||)).

Also, b = arccos(P1 * P3 / (||P1|| * ||P3||)).

Now, c_t = pi - (a_t + b), and we can use the sine relations to find l_t.

l_t = sin(a_t) * ||P1|| / sin(c_t).

Finally, P_t = (l_t / ||P3||) * P2 + ((||P3|| - l) / ||P3||) * P1, which lies on the line between P1 and P2 and lets a_t depend linearly on t.