For one arbitrary unit vector, what is the best method for computing an arbitrary orthogonal unit vector?

Essentially, the same question was asked here , but in the context of non-programming. The proposed solution is {y, -x, 0 }. This will work for all vectors that have an x ​​or y component, but will not work if the vector is + or - {0, 0, 1 }. In this case, we get {0, 0, 0 }.

My current solution (in C ++):

// floating point comparison utilizing epsilon bool is_equal(float, float); // ... vec3 v = /* some unit length vector */ // ... // Set as a non-parallel vector which we will use to find the // orthogonal vector. Here we choose either the x or y axis. vec3 orthog; if( is_equal(vx, 1.0f) ) orthog.set(1.0f, 0.0f, 0.0f); else orthog.set(0.0f, 1.0f, 0.0f); // Find orthogonal vector orthog = cross(v, orthog); orthog.normalize(); 

This method works, but I feel that there may be a better method, and my searches no longer appear.


[EDIT]

Just for fun, I made a quick code of naive implementations of each of the proposed answers in C ++ and confirmed that they all worked (although some of them do not always return a unit vector, naturally, I added the noramlize () call where necessary).

My original idea:

 vec3 orthog_peter(vec3 const& v) { vec3 arbitrary_non_parallel_vec = vx != 1.0f ? vec3(1.0, 0.0f, 0.0f) : vec3(0.0f, 1.0f, 0.0f); vec3 orthog = cross(v, arbitrary_non_parallel_vec); return normalize( orthog ); } 

stack overflow

 vec3 orthog_robert(vec3 const& v) { vec3 orthog; if(vx == 0.0f && vy == 0.0f) orthog = vec3(1.0f, 1.0f, 0.0f); else if(vx == 0.0f) orthog = vec3(1.0f, vz / vy, 1.0f); else if(vy == 0.0f) orthog = vec3(-vz / vx, 1.0f, 1.0f); else orthog = vec3(-(vz + vy) / vx, 1.0f, 1.0f); return normalize(orthog); } 

stack overflow

 // NOTE: u and v variable names are swapped from author example vec3 orthog_abhishek(vec3 const& v) { vec3 u(1.0f, 0.0f, 0.0f); float u_dot_v = dot(u, v); if(abs(u_dot_v) != 1.0f) return normalize(u + (v * -u_dot_v)); else return vec3(0.0f, 1.0f, 0.0f); } 

stack overflow

 vec3 orthog_dmuir(vec3 const& v) { float length = hypotf( vx, hypotf(vy, vz)); float dir_scalar = (vx > 0.0) ? length : -length; float xt = vx + dir_scalar; float dot = -vy / (dir_scalar * xt); return vec3( dot * xt, 1.0f + dot * vy, dot * vz); }; 
+3
source share
4 answers

Well, here is one way to get around this. Let a vector (a, b, c) be given. Solve the equation (a, b, c) dot (aa, bb, cc) = 0 for aa, bb and cc (and make sure that aa, bb and cc are not all equal to zero), therefore (aa, bb, cc) is orthogonal (a, b, c). I used Maxima ( http://maxima.sf.net ) to solve this problem.

 (%i42) solve ([a, b, c] . [aa, bb, cc] = 0, [aa, bb, cc]), a=0, b=0; (%o42) [[aa = %r19, bb = %r20, cc = 0]] (%i43) solve ([a, b, c] . [aa, bb, cc] = 0, [aa, bb, cc]), a=0; %r21 c (%o43) [[aa = %r22, bb = - ------, cc = %r21]] b (%i44) solve ([a, b, c] . [aa, bb, cc] = 0, [aa, bb, cc]), b=0; %r23 c (%o44) [[aa = - ------, bb = %r24, cc = %r23]] a (%i45) solve ([a, b, c] . [aa, bb, cc] = 0, [aa, bb, cc]); %r25 c + %r26 b (%o45) [[aa = - ---------------, bb = %r26, cc = %r25]] a 

Please note that at first I decided on special cases (a = 0 and b = 0, or = 0, or b = 0), since the solutions found are not all valid for some components equal to zero. The variables% r that appear are arbitrary constants. I set them to 1 to get some specific solutions.

 (%i52) subst ([%r19 = 1, %r20 = 1], %o42); (%o52) [[aa = 1, bb = 1, cc = 0]] (%i53) subst ([%r21 = 1, %r22 = 1], %o43); c (%o53) [[aa = 1, bb = - -, cc = 1]] b (%i54) subst ([%r23 = 1, %r24 = 1], %o44); c (%o54) [[aa = - -, bb = 1, cc = 1]] a (%i55) subst ([%r25 = 1, %r26 = 1], %o45); c + b (%o55) [[aa = - -----, bb = 1, cc = 1]] a 

Hope this helps. Good luck and keep up the good work.

+1
source

Another way is to use homeowner reflectors .

We can find a reflector Q that maps our vector to a multiple (1,0,0). Applying Q to (0,1,0), we get a vector perpendicular to our vector. One of the advantages of this method is that it applies to any number of measurements; the other is that we can get another vector (s) perpendicular to the original and new: apply Q to (0,0,1). It may seem complicated, but here the C code for 3d (xp, yp, zp is a required vector and has a length of 1, since everything is written that everything is double, but you can use float instead and use hypotf instead of hypot)

 l = hypot( x, hypot(y,z)); s = (x > 0.0) ? l : -l; xt = x + s; dot = -y/(s*xt); xp = dot*xt; yp = 1.0 + dot*y; zp = dot*z; 
+3
source

You need to choose a point v that is not equal to zero, and not on the line connecting the beginning with the given unit vector u.

As already suggested, you can select a unit vector on any axis if this point satisfies the above condition. If u already lies on the axis, then simply select any other axis for v.

Then you need to solve the equation (v + tu).u = 0 . (just solve for t)

Of course, you will need to normalize it to get an orthogonal unit vector.

enter image description here

+1
source

Here is the C version that uses the dominant axis to get a more deterministic result.

The caller must normalize the result of ortho_v3_v3 .

 inline int axis_dominant_v3_single(const float vec[3]) { const float x = fabsf(vec[0]); const float y = fabsf(vec[1]); const float z = fabsf(vec[2]); return ((x > y) ? ((x > z) ? 0 : 2) : ((y > z) ? 1 : 2)); } /** * Calculates \ap - a perpendicular vector to \av * * \note return vector won't maintain same length. */ void ortho_v3_v3(float p[3], const float v[3]) { const int axis = axis_dominant_v3_single(v); assert(p != v); switch (axis) { case 0: p[0] = -v[1] - v[2]; p[1] = v[0]; p[2] = v[0]; break; case 1: p[0] = v[1]; p[1] = -v[0] - v[2]; p[2] = v[1]; break; case 2: p[0] = v[2]; p[1] = v[2]; p[2] = -v[0] - v[1]; break; } } 
+1
source

Source: https://habr.com/ru/post/1413743/


All Articles