Given two arbitrary vectors $\textbf{v}_1$ and $\textbf{v}_2$, how can I draw the plane which they span?
-
3$\begingroup$ 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... $\endgroup$– J. M.'s slightly less busy ♦Feb 7, 2012 at 23:06
8 Answers
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}]}]
}]
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}]
-
$\begingroup$ Yeah, this is definitely much better than my idea. $\endgroup$– David ZFeb 7, 2012 at 22:53
-
1$\begingroup$ 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 yielding0
, but it doesn't, and similarly for the version wherev1
is replaced byv2
. There is a simple fix: usenn = Normalize[Cross[v1 - r0, v2 - r0]];
instead for computing the normal vector. $\endgroup$ Feb 8, 2012 at 5:28 -
$\begingroup$ @J.M. You are, of course, correct--thanks for the correction! I am fixing my answer accordingly. $\endgroup$– CassiniFeb 8, 2012 at 15:30
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}]}]
-
$\begingroup$ just ahead of me again! serves me right for trying to put a nice texture on it... $\endgroup$– aclFeb 7, 2012 at 22:55
-
$\begingroup$ @acl Blame David Zaslavsky. I was busy typing a ParametricPlot3D solution but had to switch tactics when his solution popped up. $\endgroup$– HeikeFeb 7, 2012 at 23:02
-
1
-
1$\begingroup$ 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. $\endgroup$– David ZFeb 7, 2012 at 23:04
-
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.
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]]
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}
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]}]}}]]
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]}]}}]]
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]
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}}]