Mathematica Stack Exchange is a question and answer site for users of Mathematica. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

With Graphics3D[Sphere[{0, 0, 0}, 1]], I can render a uniform 3D sphere, but how can I render an ellipsoid? I would need to specify the rotation of the ellipsoid and the length of the main axes. The method should be reasonably fast to display around 100 of them at once.

share|improve this question
    
related – gpap Oct 29 '13 at 16:25
2  
Look up GeometricTransformation – Simon Woods Oct 29 '13 at 16:36
    
This uses ContourPlot3D: demonstrations.wolfram.com/Ellipsoid – KAI Oct 29 '13 at 16:56
1  
There is also an Ellipsoid function in the MultivariateStatistics package that I used here, but it acts cranky at times... – R. M. Oct 29 '13 at 23:12
up vote 10 down vote accepted

You can modify this if you need to specify the rotation in different ways, etc. As Simon Woods has suggested, probably the best way is to use GeometricTransformation.

 ellipsoid[a_, b_, center_?VectorQ, rotation_, around_?VectorQ] := Fold[
           GeometricTransformation,
           Sphere[],
           {ScalingTransform[{a, b, b}],
            RotationTransform[rotation, around],
            TranslationTransform[center]}]

 ellipsoid @@@ Table[{x, x, 10 {x, x, x}, x, {x, x, x}} /. x :> RandomReal[]
                     , {111}] // Graphics3D // AbsoluteTiming
{0.347020,

enter image description here

share|improve this answer
2  
I had a slight wtf moment at all the x's - nice way to generate the data. – Simon Woods Oct 29 '13 at 21:15
    
@SimonWoods uff I was afraid I've missed something :) – Kuba Oct 29 '13 at 21:21
1  
You can compose the transforms with Dot instead of Fold: TranslationTransform[center].RotationTransform[rotation, around].ScalingTransform[{a, b, b}]. Very nice, +1! – Michael E2 Oct 30 '13 at 0:15
    
@MichaelE2 Thanks ;) and yes Dot looks clear and is about 3% faster than Fold on my pc. – Kuba Oct 30 '13 at 3:17
    
Dot[] works, but Composition[] is the documented way to compose geometric transforms: GeometricTransformation[Sphere[], Composition[TranslationTransform[center], RotationTransform[rotation, around], ScalingTransform[{a, b, b}]]] – J. M. Jul 21 at 1:37

Using Sphere with Scale and Rotate works too:

Graphics3D[Rotate[Scale[Sphere[], {5, 4, 2}, {0, 0, 0}], 60 Degree, {1, 2, 1}]]

enter image description here

The first triple is the scaling in the x,y,and z coordinates, the second triple is the translation, and the third triple is the axis about which to rotate. To generate a number of random ellipses:

x := RandomReal[];
Show[Table[Graphics3D[Rotate[Scale[Sphere[], {x, x, x}, {x i/6, x i/6, x i/6}], 
                      x, {x, x, x}], Boxed -> False], {i, 25}]]

enter image description here

share|improve this answer

An alternative approach that generates explicit primitives instead of transformed ones uses the NURBS representation of a sphere, with all the appropriate transformations done to its control points to generate the ellipsoid:

myEllipsoid[dims : {_?Positive, _?Positive, _?Positive} : {1, 1, 1}, 
            center : (_?VectorQ) : {0, 0, 0}, 
            rot : {_, _?VectorQ} : {0, {1, 0, 0}}] := Block[{ctrlpts},
  ctrlpts = Composition[TranslationTransform[center], 
                        RotationTransform[Sequence @@ rot],
                        ScalingTransform[dims]] /@ 
            Outer[Append[#2 #1[[1]], #1[[2]]] &,
                  {{0, -1}, {1, -1}, {1, 1}, {0, 1}},
                  {{1, 0}, {1, 1}, {-1, 1}, {-1, 0}, {-1, -1}, {1, -1}, {1, 0}}, 1];
            BSplineSurface[ctrlpts, SplineClosed -> True, SplineDegree -> 2, 
                           SplineKnots -> {{0, 0, 0, 1/2, 1, 1, 1},
                                           {0, 0, 0, 1/4, 1/2, 1/2, 3/4, 1, 1, 1}}, 
                           SplineWeights -> Outer[Times, {1, 1/2, 1/2, 1},
                                                  {1, 1/2, 1/2, 1, 1/2, 1/2, 1}]]]

Here's an example:

randomEllipsoid := myEllipsoid[RandomReal[1, 3], RandomReal[{-2, 2}, 3],
                               {RandomReal[{-π, π}], 
                                Normalize[RandomVariate[NormalDistribution[], 3]]}]

BlockRandom[SeedRandom[42, Method -> "Legacy"]; 
            Graphics3D[Table[{ColorData[61, RandomInteger[{1, 9}]], randomEllipsoid},
                             {50}], Boxed -> False, Lighting -> "Neutral"]]

some ellipsoids

share|improve this answer

Starting from version 10 there is documented Ellipsoid which is reasonably fast

Graphics3D[Ellipsoid @@@ RandomReal[1, {100, 2, 3}]]

enter image description here

For an arbitrary orientation you specify the weight matrix Σ as a second argument

randomEllipsoid[] := Module[{ℛ, \[ScriptCapitalS], p},
  ℛ = First@QRDecomposition@RandomReal[NormalDistribution[], {3, 3}];
  \[ScriptCapitalS] = DiagonalMatrix@RandomReal[1, 3];
  p = RandomReal[10, 3];
  Ellipsoid[p, ℛ\[Transpose].\[ScriptCapitalS].ℛ]]

Graphics3D[Table[randomEllipsoid[], {100}]]

enter image description here

Here and \[ScriptCapitalS] are random rotation matrix and random scale matrix respectively.

share|improve this answer
    
Its only limitation is that it can only generate axis-aligned ellipsoids; Rotate[] is still needed for the arbitrary orientation. – J. M. Nov 17 '15 at 14:51
    
@J.M. What about Graphics3D[Ellipsoid[{0, 0, 0}, {{5, 2, 3}, {2, 3, 2}, {3, 2, 5}}]]? :) – ybeltukov Nov 17 '15 at 14:54
    
Ah, missed that. :D One still has to recognize the SVD for this. Anyway: First @ QRDecomposition @ RandomReal[NormalDistribution[], {3, 3}] is more compactly done as Orthogonalize[RandomReal[NormalDistribution[], {3, 3}]]. – J. M. Nov 17 '15 at 15:09
    
@J.M. Sure, it is just a habit because it is faster for big matrices. – ybeltukov Nov 17 '15 at 15:31
    
That's funny… maybe it's worth a question? – J. M. Nov 17 '15 at 15:33

Thought I would add after looking at this quite a bit later. The numbers you use to generate the random ellipsoid orientation is not truly random. You are missing a factor of pi/2 in the 4th argument in the table.

When generating the table use this instead to get truly random ellipsoids:

 ellipsoid @@@ Table[{x, x, 10 {x, x, x}, pi/2*x, {x, x, x}} /. x :> RandomReal[]
                     , {111}] // Graphics3D // AbsoluteTiming

All I added was a factor of pi in the 4th argument of ellipsoid in the table being generated. This will give you random radian values from 0 to pi/2.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.