Sign up ×

I would like to create randomly oriented planes. This is how I'm attempting to do that:

  1. I create a 2 random unit vectors, $\mathbf{v}_1$, and $\mathbf{v}_2$, in the $x$-$y$ plane
  2. I assume that if I rotate these two vectors around a random vector (in $x$-$y$-$z$) called $\mathbf n$, the plane on which the two vectors lie is random and uniformly distributed over the sphere.
  3. So I randomly pick $\mathbf n$, keeping in mind the issues of random point picking on spheres.
  4. I then use RotationMatrix[α, n].v1 (and same for v2) to get the new vectors on the rotated and supposedly random plane. There is some question on what to choose for the angle $\alpha$ which gives the angle of the rotation.
    • If I choose $\alpha<\pi/2$, the vectors do not encompass the entire sphere.
    • If I choose $\alpha=\pi/2$, I get a bunching of vectors at the poles.
    • If I choose $\alpha>\pi/2$, there is bunching at various latitudes. I cannot get a uniformly random distribution over the sphere!

Is there a fix to the current method I am implementing? Is there another way to do it?

My real goal here isn't creating random planes. My goal is to take two vectors with some arbitrary magnitude and direction in $x$-$y$ and then randomly orient them over the sphere while maintaining their relative positions with respect to one another. The steps I have taken above seem like the logical way to do that.

share|improve this question
Isn't this the same as re-orienting $\mathbf{v}_1 \times \mathbf{v}_2$ to some arbitrary direction? –  rcollyer Feb 2 '12 at 19:09
@rcollyer I thought the same –  Rojo Feb 2 '12 at 19:37

2 Answers 2

up vote 10 down vote accepted

Why don't you pick a random vector on the sphere to be your first vector, instead of $\mathbf{n}$, and then pick a random uniform number between $0$ and $2 \pi$ to orient the second vector aronud the first?

Something like this, assuming you have your function randomVectorOnUnitSphere[] already (haven't tested it)

generateRandomPositioning[v1_, v2_] := 
 With[{angle = VectorAngle[v1, v2], mag1 = Norm[v1], mag2 = Norm[v2], 
   rvec = randomVectorOnUnitSphere[]},
  Module[{v1out, v2out},
   v1out = rvec mag1;
   v2out = 
    Cross[rvec, v2] //
      (* this just gives a particular vector perpendicular to v2out, 
      assuming they are not colinear *) 
      RotationTransform[angle, #][rvec] & //
      (* now I have a particular vector at the corresponding angle of v1out *) 
      RotationTransform[RandomReal[2 Pi], rvec]//(* now it's distributed uniformly *) 
      Normalize[#] mag2 &;
    {v1out, v2out}

Ok, here's my test

randomVectorOnUnitSphere[]:=With[{θ = RandomReal[2 π], φ = ArcCos[RandomReal[{-1,1}]]},
    {Cos[θ] Sin[φ],Sin[φ] Sin[φ],Cos[φ]}

ListPointPlot3D[Table[randomVectorOnUnitSphere[], {10000}], AspectRatio -> 1]

enter image description here

In[28]:= v1 = {0, 1, 1}; v2 = {0, 3, 0.4};
test = Table[generateRandomPositioning[v1, v2], {500}];

In[13]:= arrowCouple[{pt1_, pt2_}] := {Arrow[{{0, 0, 0}, pt1}], 
   Arrow[{{0, 0, 0}, pt2}]};

In[30]:= Equal @@ VectorAngle @@@ test

Out[30]= True

In[31]:= VectorAngle @@ First@test == VectorAngle[v1, v2]

Out[31]= True

   0.2], {RGBColor[RandomReal[], RandomReal[], RandomReal[]], 
     arrowCouple[#]} & /@ test}, Boxed -> False]

enter image description here

Graphics3D[{Black, arrowCouple[{v1, v2}], 
     arrowCouple[#]} & /@ test[[;; 3]]}, Boxed -> False]

enter image description here

I know, these aren't proper tests, nor am I sure this is what you want to accomplish.

If I think about it more formally, and I remember well, you need to have a clear idea of how you measure sets of "pairs of vectors of given magnitude and angle between them", so that you can talk about uniform distribution. It would mean that the probabilty of the final pair of vectors being in a certain subset is proportional to the subset's measure... But if we assume that your measure is invariant to rotations, which makes sense, then probably it's all the same

share|improve this answer
thanks. I will try this. The reason I was trying it my original way was that the vector magnitudes have a normal distribution and it was easiest to assign them in the x-y coordinates. I will have to worry about that later for the time being. –  BeauGeste Feb 2 '12 at 19:34
Let me see if I understand what you did: So you start with the two vectors v1 and v2. You assign v1out to a random vector on the sphere. To get v2out you take cross product of v2 and random vector. v1out and Cross[rvec, v2] form the new plane. Now you transform Cross[rvec, v2] in such a way that it reestablishes its orientation with v1out in the new plane. What is the second RotationTransform doing? –  BeauGeste Feb 2 '12 at 21:15
@BeauGeste Cross[rvec, v2], that rvec is the same I used to assign the v1out. So it gives a vector that's normal to v1out. I then use that vector to rotate v1 over a perpendicular axes to itself, the angle wanted... so as to get a vector that is at the proper angle... Finally, i rotate that vector on the v1out axes to get v2out randomly distributed, while keeping the angle –  Rojo Feb 3 '12 at 8:47

If all that was really wanted was to randomly orient a plane spanned by two vectors while preserving the angle between them, then the simplest way is to generate a Haar-distributed pseudorandom orthogonal matrix, and use that to perform the random orientation. The code for generating a $3\times 3$ random orthogonal matrix is surprisingly simple:

ranOrt := Orthogonalize[RandomVariate[NormalDistribution[], {3, 3}]]

(For more than three dimensions, this isn't the most efficient method, but it works nicely here and the code is nicely short.)

Try it out:

arrowCouple[{pt1_?VectorQ, pt2_?VectorQ}] := {Arrowheads[{-.04, .04}],
   Arrow[{pt1, {0, 0, 0}, pt2}]}

 Table[Prepend[With[{m = ranOrt}, arrowCouple[{m.v1, m.v2}]], 
   Hue[RandomReal[], 1, 1, 0.2]], {100}], Boxed -> False]

randomly oriented planes spanned by arrows

(I know I can use GeometricTransformation[] for this, but I prefer the explicit approach here.)

share|improve this answer

Your Answer


