25

Given two arbitrary vectors $\textbf{v}_1$ and $\textbf{v}_2$, how can I draw the plane which they span?

BeauGeste
  • 2,815
  • 2
  • 29
  • 32
  • 3
    To give a mathematical viewpoint: both Mark's and David S.'s approaches use the Hessian normal form of a plane. I would say that if you're trying to do anything mathematical in Mathematica, MathWorld is one of those places you should try looking for formulae in... – J. M.'s missing motivation Feb 07 '12 at 23:06

9 Answers9

20
SeedRandom[3];
{v1, v2} = RandomReal[{-2, 2}, {2, 3}];
n = Cross[v1, v2];
Show[{
  ContourPlot3D[n.{x, y, z} == 0, {x, -2, 2}, {y, -2, 2}, {z, -2, 2},
    ContourStyle -> Opacity[0.5], Mesh -> False],
  Graphics3D[{Arrow[{{0, 0, 0}, v1}], Arrow[{{0, 0, 0}, v2}]}]
}]

Mathematica graphics

Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
Mark McClure
  • 32,469
  • 3
  • 103
  • 161
12

Here's an example of how you could do it:

v1 = {1, -1/2, -1.9}; (* pick something *)
v2 = {0, 1, -1}; (* pick something *)
r0 = {-1/2, 1/2, 3/4}; (* point in the plane; pick something *)

nn = Normalize[Cross[v1-r0, v2-r0]];
r = {rx, ry, rz};
sol = Solve[Dot[nn, (r - r0)] == 0, {rz}] // Simplify
Plot3D[rz /. sol, {rx, -10, 10}, {ry, -10, 10}]

enter image description here

Cassini
  • 5,556
  • 5
  • 28
  • 38
  • Yeah, this is definitely much better than my idea. – David Z Feb 07 '12 at 22:53
  • 1
    It seems you've misapplied the formula for the Hessian normal form here. (rz - Last[v1] /. First[Solve[Dot[nn, (r - r0)] == 0, {rz}]]) /. Thread[{rx, ry} -> Take[v1, 2]] ought to be yielding 0, but it doesn't, and similarly for the version where v1 is replaced by v2. There is a simple fix: use nn = Normalize[Cross[v1 - r0, v2 - r0]]; instead for computing the normal vector. – J. M.'s missing motivation Feb 08 '12 at 05:28
  • @J.M. You are, of course, correct--thanks for the correction! I am fixing my answer accordingly. – Cassini Feb 08 '12 at 15:30
12

Another option is to use Graphics3D primitives

Graphics3D[Polygon[{{0,0,0},v1,v1+v2,v2}]]

Edit

J.M. already gave one way to produce a square spanned by the two vectors as a Polygon. Another way would be to use Rotate:

{v1, v2} = RandomReal[{-1, 1}, {2, 3}]

Graphics3D[{
  Rotate[Polygon[{{-1, -1, 0}, {1, -1, 0}, {1, 1, 0}, {-1, 1, 0}}],
    {{0, 0, 1}, Cross[v1, v2]}],
  Arrow[{{0, 0, 0}, v1}],
  Arrow[{{0, 0, 0}, v2}]}]

Mathematica graphics

Heike
  • 35,858
  • 3
  • 108
  • 157
  • just ahead of me again! serves me right for trying to put a nice texture on it... – acl Feb 07 '12 at 22:55
  • @acl Blame David Zaslavsky. I was busy typing a ParametricPlot3D solution but had to switch tactics when his solution popped up. – Heike Feb 07 '12 at 23:02
  • 1
    I think this is the most elegant – acl Feb 07 '12 at 23:04
  • 1
    The problem with this method (and mine as well) is that you don't get the whole plane, only the piece of it that is directly bounded by the given vectors. So while it is elegant, I think you're answering something a little different from what the question is actually looking for. – David Z Feb 07 '12 at 23:04
  • @acl at least it's the shortest. – Heike Feb 07 '12 at 23:05
  • @David on the other hand, you can't actually draw the whole plane spanned by them, as the question asks :) – acl Feb 07 '12 at 23:06
  • @acl: heh, true :-) Naturally, I meant that with this solution and mine, the bounds of the region of the plane which is rendered need to be set separately from the bounds of the plot region, as opposed to Mark's and (other) David's solutions which automatically plot as much of the plane as will fit in the specified axes. – David Z Feb 07 '12 at 23:09
  • Of course, one could modify Heike's approach (which is important since you effectively use just one Polygon[] for your plane) by orthogonalizing and then multiplying your now-orthogonal vectors with a scale factor. – J. M.'s missing motivation Feb 07 '12 at 23:16
  • @J.M. The number of Polygons used in for example David Skulsky's solution can be reduced quite a bit by setting PlotPoints->2, MaxRecursion->1. – Heike Feb 07 '12 at 23:23
7

If your vectors are three-element lists, here's one way (though I really feel like a hack for suggesting this):

ParametricPlot3D[u v1 + v v2, {u,-1,1},{v,-1,1},
  PlotRange->{{-1,1},{-1,1},Automatic}]

You may have to adjust the limits of -1 and 1 depending on how much of the plane you want to plot.

David Z
  • 4,921
  • 4
  • 25
  • 35
7

I present here a modification of Heike's approach that might be attractive for some applications; it produces a square with side length c as a Polygon[] object, representing the plane spanned by v1 and v2, with origin at r0:

v1 = {1, -1/2, -19/10}; v2 = {0, 1, -1}; (* spanning vectors *)
r0 = {-1/2, 1/2, 3/4}; (* origin *)
{o1, o2, o3} = Orthogonalize[Append[#, Cross @@ #]] &[{v1 - r0, v2 - r0}];
With[{c = 6}, (* generate a c×c square *)
   Graphics3D[{{Directive[EdgeForm[], Gray], 
      Polygon[{r0 + c (o1 + o2)/2, r0 - c (o1 - o2)/2, 
               r0 - c (o1 + o2)/2, r0 + c (o1 - o2)/2}]},
              {Red, Arrow[{r0, v1}], Arrow[{r0, v2}]},
              {Blue, Arrow[{r0, r0 + Cross[v1 - r0, v2 - r0]}]}},
              Boxed -> False, Lighting -> "Neutral", PlotRange -> All]]

square spanned by vectors

As can be seen from the code, the trick is in producing mutually orthogonal unit vectors via Orthogonalize[] (for older versions, use QRDecomposition[] instead and take the $\mathbf Q$ factor) that can be nicely scaled/combined afterwards.

Here's how to verify that a square is indeed produced as claimed:

FullSimplify[Map[Norm, Differences[Append[#, First[#]]]]&[{r0 + c (o1 + o2)/2, 
             r0 - c (o1 - o2)/2, r0 - c (o1 + o2)/2, r0 + c (o1 - o2)/2}], c > 0]
{c, c, c, c}
J. M.'s missing motivation
  • 124,525
  • 11
  • 401
  • 574
5

Interactive - drag orange dots around.

Manipulate[ Graphics3D[{{Blue, Opacity[.5], Polygon[{{-1, -1, 0}, {1, -1, 0}, 
{1, 1, 0}, {-1, 1, 0}}]}, {Red, Thick, Arrow[{{0, 0, 0}, Flatten@{p, 0}}]}, 
{Black, Thick, Arrow[{{0, 0, 0}, Flatten@{q, 0}}]}}, SphericalRegion -> True, 
Boxed -> False, ViewAngle -> .37],{{p, {1, 0}}, {-1, -1},{1, 1}},{{q, {0, 1}}, 
{-1, -1}, {1, 1}}, ControlPlacement -> Left]

enter image description here

Vitaliy Kaurov
  • 73,078
  • 9
  • 204
  • 355
5

Using

v1 = {1, -1/2, -19/10}; v2 = {0, 1, -1}; (* spanning vectors *)
r0 = {-1/2, 1/2, 3/4}; (* origin *)

as a concrete example, I present here, for giggles, variations of Mark's and David Skulsky's answers, based on formula 18 here.

Mark:

Show[ContourPlot3D[
  Det[PadRight[{{x, y, z}, r0, v1, v2}, {4, 4}, 1]] == 0, {x, -3, 
   3}, {y, -3, 3}, {z, -3, 3}, BoxRatios -> Automatic, 
  ContourStyle -> Opacity[0.5], Mesh -> False], 
 Graphics3D[{{Red, Arrow[{r0, v1}], Arrow[{r0, v2}]}, {Blue, 
    Arrow[{r0, r0 + Cross[v1 - r0, v2 - r0]}]}}]]

plane spanned by vectors, ContourPlot3D[] version.

David (plus Heike's suggestion):

Show[Plot3D[
  Evaluate[z /. 
    First[Solve[
      Det[PadRight[{{x, y, z}, r0, v1, v2}, {4, 4}, 1]] == 0, 
      z]]], {x, -2, 2}, {y, -2, 2}, BoxRatios -> Automatic, 
  MaxRecursion -> 1, Mesh -> 0, PlotPoints -> 2], 
 Graphics3D[{{Red, Arrow[{r0, v1}], Arrow[{r0, v2}]}, {Blue, 
    Arrow[{r0, r0 + Cross[v1 - r0, v2 - r0]}]}}]]

plane spanned by vectors, Plot3D[] version.

J. M.'s missing motivation
  • 124,525
  • 11
  • 401
  • 574
4
SeedRandom[1]
{v1, v2} = RandomReal[{-5, 5}, {2, 3}];

Graphics3D[{Arrow[{{0, 0, 0}, v1}], Arrow[{{0, 0, 0}, v2}]}, 
 ClipPlanes -> InfinitePlane[{{0, 0, 0}, v1, v2}], 
 ClipPlanesStyle -> Opacity[0.3, Green], 
 PlotRange -> {{-5, 5}, {-5, 5}, {-5, 5}}]

Mathematica graphics

kglr
  • 394,356
  • 18
  • 477
  • 896
1

If vectors are no parallel, you can get a nice orthonormal basis for the plane so you can control the plane sides.

v1 = {1, -1/2, -19/10}; v2 = {0, 1, -1};(*spanning vectors*)

{u, v} = Orthogonalize[{v1, v2}]; Graphics3D[{(Plane) First@ParametricPlot3D[t u + s v, {t, -1, 2}, {s, -3, 2.5}, Mesh -> None, PlotStyle -> {Opacity[0.4], Gray}], (First@ParametricPlot3D[t v1 + s v2, {t, -1, 2}, {s, -3, 2.5}, Mesh -> None, PlotStyle -> {Opacity[0.4], Gray}],) (Vectors) Arrowheads[{0.06}], AbsoluteThickness[3.5], Arrow[{{0, 0, 0}, v1}], Orange, Arrow[{{0, 0, 0}, v2}] }, Boxed -> False, ViewPoint -> {3, 0.09, 1.3}]

enter image description here

Or simply you can draw an paralelogram

   v1 = {1, -1/2, -19/10}; v2 = {0, 1, -1}; or3 = {0, 0, 0};
    Graphics3D[{(*Plane*)
      EdgeForm[Thin], 
      FaceForm[{Gray, Opacity[0.1]}], Polygon[{v1, or3, v2, v1 + v2}],
      (*Vectors*)
      Arrowheads[{0.06}], AbsoluteThickness[3.5],
       Arrow[{{0, 0, 0}, v1}], Orange, Arrow[{{0, 0, 0}, v2}]
      }, Boxed -> False, ViewPoint -> {3, 0.09, 1.3}]

enter image description here

wmora2
  • 589
  • 2
  • 9