29
$\begingroup$

There is no Circle or Disk object in 3D. I quickly found a way to use Cylinder (thin lines, no faces, very flat):

Module[{s},
Graphics3D[{EdgeForm[Thickness[Small]], FaceForm[None], 
  Cylinder[{s = {1/2, 1/2, 1/2}, s + {0, 1/1000, -2/1000}}, 1/2]}, 
  Axes -> True, AxesLabel -> {"x", "y", "z"}, 
  PlotRange -> {{0, 1}, {0, 1}, {0, 1}}]]

3D circle

But

  • orientation of the cylinder is tricky,
  • choice of coordinate shift is dependent on graphics size and magnification. I have to take into account the parameters of relative thickness,
  • it requires me to make a few auxiliary functions (without speaking for instance if I want to define a circle by center, radius and angles to the axis, or by three points)
  • I cannot only draw an arc between 2 angle positions nor make it elliptical.

If I want all this, am I forced to recreate the wheel and construct computationally a 3D polygon approximating an ellipse ?

$\endgroup$
4
  • 1
    $\begingroup$ I'm surprised Cylinder[] does not degenerate gracefully if the endpoints given to it are identical. For a circle arc in 3D, I don't think there's a built-in function for that. Note that you can use ScalingTransform[] on your circles to yield ellipses when needed. $\endgroup$ Jun 7, 2012 at 16:05
  • 1
    $\begingroup$ What would your preferred input for your arc be? There are many ways to parametrize... $\endgroup$
    – Yves Klett
    Jun 7, 2012 at 17:20
  • 1
    $\begingroup$ @Yves Klett : thanks for your concern and your interesting answer. In fact I asked the question mainly to know if it had been done before, if there was a standard package with this kind of things (an ellipse primitive in 3D). I am able to create the various required parametrizations myself in Mathematica. $\endgroup$
    – ogerard
    Jun 8, 2012 at 5:29
  • 1
    $\begingroup$ Highly relevant: mathematica.stackexchange.com/questions/10957/… $\endgroup$ Sep 14, 2013 at 7:10

8 Answers 8

17
$\begingroup$

One way to go about drawing a circular arc defined by three points (adjust for ellipses):

{a, b, m} = {{1, 0, 0}, {-1, 1, 2}, {1, 1, 1}};

{a, b, m} = {{1, 0, 0}, {-1, 1, 2}, {1, 1, 1}};

    Arc3D[{a_, b_, m_}, n_: 60, prim_: Line] := 
      Module[{\[Alpha], lab, axis, aarc, tm, alpha},
        lab = m + Norm[a - m]*Normalize[b - m];
        axis = (a - m)\[Cross](b - m);
        aarc = (VectorAngle[a - m, b - m]);
        tm = RotationMatrix[alpha, axis];
        prim@Table[m + tm.(a - m), {alpha, 0, aarc, aarc/n}]
        ]

    Graphics3D[{PointSize[Large], Line[{m, a}], Line[{m, b}], 
        Point[{a, b, m}], Arc3D[{a, b, m}, 20]}]

Mathematica graphics

This only draws arcs up to $\pi$. I´ll try to elaborate once your specs become a bit clearer (esp. what your preferred input would look like).

$\endgroup$
5
  • 1
    $\begingroup$ As a note: three points determine a circle, but one needs five points to determine an ellipse. $\endgroup$ Jun 7, 2012 at 16:42
  • $\begingroup$ @J.M. thusly "circular arc"... never needed a 3D ellipse before ;-) $\endgroup$
    – Yves Klett
    Jun 7, 2012 at 16:45
  • $\begingroup$ Sure. :) It's more of a general reminder for everybody than anything. $\endgroup$ Jun 7, 2012 at 16:49
  • $\begingroup$ @J.M. : another reminder is that the five points must be coplanar :-) $\endgroup$
    – ogerard
    Jun 8, 2012 at 5:34
  • $\begingroup$ @Yves Klett : as it is already, your code will be quite useful to me. $\endgroup$
    – ogerard
    Jun 8, 2012 at 5:37
15
$\begingroup$

Here is something I have used before to make plots of polarization states in vector fields. It does geometric transformations on a basic shape similar to what Cylinder produces:

pacman[{θ1_, θ2_}, scale_, thickness_, capStyle_, 
  wedgeStyle_] := {{capStyle, 
   RevolutionPlot3D[
     thickness, {t, 0, scale}, {θ, θ1, θ2}, 
     Mesh -> False][[1]],
   RevolutionPlot3D[-thickness, {t, 0, 
      scale}, {θ, θ1, θ2}, Mesh -> False][[1]]},
  RevolutionPlot3D[{scale, t}, {t, -thickness, 
     thickness}, {θ, θ1, θ2}, Mesh -> False][[1]],
  {wedgeStyle, 
   Polygon[{{0, 0, -thickness}, {scale Cos[θ1], 
      scale Sin[θ1], -thickness}, {scale Cos[θ1], 
      scale Sin[θ1], thickness}, {0, 0, 
      thickness}, {scale Cos[θ2], scale Sin[θ2], 
      thickness}, {scale Cos[θ2], 
      scale Sin[θ2], -thickness}}]}}

ellipse3D[abrList_, wedgeList_: {{0, 2 π}}, scale_: .1, 
  thickness_: .01, capStyle_: {}, wedgeStyle_: {}] :=
 {EdgeForm[],
  MapThread[GeometricTransformation[{
      pacman[#2, scale, thickness, capStyle, wedgeStyle]
      },
     AffineTransform[{
       Transpose[
        Append[Most[#], Normalize[Cross @@ Most[#]]]], Last[#]}
      ]] &,
   {abrList, PadRight[wedgeList, Length[abrList], {Last[wedgeList]}]}]}

Edit

In the above code, I added the ability to draw a filled "arc" of an ellipse, more commonly known as a squished Pacman. The examples below stay the same if you don't specify a pair of angles for the wedge in the ellipse. I'll add an example with a wedge opening below.

Graphics3D[{
  Red,
  ellipse3D[{
    {
     (* Axes a, b, position r: *)
     {1, 0, 0}, {0, .5, 0}, {0, 0, 0}
     }
    }
   ]
  }]

ellipse3d

The function ellipse3D takes a list of points as its argument, so that I can plot more than a single ellipse at a time. Each element of the list consists of a three entries:

{a, b, r}

where a and b are three-dimensional vectors pointing in the direction of the semi-major and semi-minor axes. Their length determines the eccentricity of the ellipse. If a and b aren't perpendicular to each other, you can also produce a skewed ellipse. The third vector r is the position at which the ellipse is centered.

The optional arguments scale and thickness determine the overall size of the object. The lengths given by a and b are multiplied by scale before plotting, and the z height of the cylinder which represents the ellipse in 3D is given by thickness.

Here is another example that shows how to apply it with a list of ellipses:

Graphics3D[{
  Magenta,
  ellipse3D[{
    {
     (* First ellipse; axes a, b, 
     position r: *)
     {1/Sqrt[2], 1/Sqrt[2], 0}, {0, .5, 0}, {0, 0,
       0}
     },
    {
     (* Second ellipse; axes a, b, 
     position r: *)
     {.5, 1, .5}, {.25, .25, .5}, {1, 1, 1}
     },
    {
     (* Third ellipse; axes a, b, 
     position r: *)
     {-.5, .1, 1/Sqrt[2]}, {0, .5, 0}, {0, 1, 
      0.5}
     },
    {
     (* Circle: *)
     {1, 0, 1}, {0, 1, 0}, {.5, 1, 0}
     }
    }]
  }, ViewPoint -> Top]

more ellipses

Here is an ellipse with a wedge:

Graphics3D[{
  Red,
  ellipse3D[{
    {
     (* Axes a, b, position r: *)
     {1, 0, 0}, {0, .5, 0}, {0, 0, 0}
     }
    }
   , {{0, 5}}
   ]
  }]

wedge

The second argument (wedgeList) of ellipse3D now was specified as a list of angle pairs - one for each ellipse to be drawn. If there is only a single element, all subsequent ellipses specified by the first argument (abrList) are drawn with the same angle spans.

Edit 2

In order to also be able to draw open ellipse arcs I added two further arguments to the function, specifying the style in which the different faces of the ellipse are rendered. For the top and bottom faces, the style is in the variable capStyle (with the default value capStyle = {} cap style is taken from the enclosing graphics). The sides of the wedge can be styled with the last argument, wedgeStyle. To suppress any of these, use FaceForm[].

For example, here is a hollow pacman:

Graphics3D[{
  Red,
  ellipse3D[{
    {
     (* Axes a, b, position r: *)
     {1, 0, 0}, {0, .5, 0}, {0, 0, 0}
     }
    }
   , {{0, 5}}, .1, .01, FaceForm[], Directive[Opacity[.5], Blue]
   ]
  }]

hollowpacman

As an application example, I'll just show a more complicated plot made with this kind of function. It requires too many additional definitions to put into this answer, but you can get a better impression of how 3D ellipses can be really useful:

sphericalHarmonic

$\endgroup$
12
$\begingroup$

What about using the graphics primitive that can be extracted from ParametricPlot?

arc = ParametricPlot[{2 Cos[t], Sin[t]}, {t, 0, Pi}, 
    Axes -> None][[1, 1, 3, 2, 1]];

We then add a constant value for the third dimension:

zeros = Table[0, {Length[arc]}];
arc3D = Partition[Flatten[Transpose[{arc, zeros}]], 3];

We can then use this as a 3D graphics primitive:

Graphics3D[
 GeometricTransformation[
  Line[arc3D], {RotationMatrix[45 Degree, {1, 0, 0}], {0, 0, 1}}], 
 AspectRatio -> 1, SphericalRegion -> True, 
 PlotRange -> {{-3, 3}, {-3, 3}, {-3, 3}}]

arc

$\endgroup$
1
  • 1
    $\begingroup$ Nice reuse of existing Mathematica functions that can be applied to many other things. But indeed, the simplest would perhaps be to use ParametricPlot3D directly? $\endgroup$
    – ogerard
    Jun 8, 2012 at 5:32
6
$\begingroup$

You may try

Graphics3D[{FaceForm[None], Cylinder[{{0, 0, 0}, {1, 1, 1}/1000}, 2]}]

for a circle. With a color instead of FaceForm you get a disk

Graphics3D[{Red, Cylinder[{{0, 0, 0}, {1, 1, 1}/1000}, 2]}]

Another way is to use e.g. ParametricPlot3D and applying some transformations as J.M. suggested in his comment.

$\endgroup$
5
$\begingroup$

Composed this using parametric equation of a plane:

Ellipse3D[a_, b_, P0_, n1_, n2_, Op_] := Module[{},
     ParametricPlot3D[P0 +
     (a Cos[phi]) Normalize[n1] + 
     (b Sin[phi]) Normalize[n2], 
     {phi, -Pi, Pi}, Op]

Here's how:

X = x0 + t1 S1 + t2 S2 , where

    X -> {X1, X2, X3} is translated point from (X1, X2) plane to (X1, X2, X3) space,
    x0 -> {x1, x2, x3} is translation offset from coordinate origin 
        (desired ellipse center-point P0),
    S1 -> {U1, U2, U3} and S2 -> {V1, V2, V3} 
        are base vectors of the translated coordinate system, thus they become
        normalized vectors of the desired directions of ellipse's 
        semi-major and -minor axis respectively,
    t1 and t2 are plane parameters.
    From ellipse's parametric form they become t1 = a Cos[phi] and t2 = b Sin[phi],
    a and b being the semi-major and -minor axis lengths.

Op is vector for plotting options.

Here's an example:

Show[Ellipse3D[3,2,P0,R1,R2,PlotStyle -> {Blue, Thin}],
Ellipse3D[3,2,P0,{1,0,0},{0,1,0},PlotStyle -> {Blue, Dashed}],
Graphics3D[Arrow[{P0,P0+R1}]],
Graphics3D[Arrow[{P0,P0+R2}]],AxesLabel -> {"X","Y","Z"}, PlotRange -> Automatic ] 

]

The dashed blue line represents the untranslated ellipse on X-Y plane and the continous "blue" ellipse is the one translated to XYZ space.

Plotting parameters:

P0 = {1,1,1};
R1 = {-Sqrt[2]/2, 1, 0};
R2 = {1, Sqrt[2]/2, 1};
$\endgroup$
4
$\begingroup$

You can use the new "SplineCircle" ResourceFunction to do this. Example:

Graphics3D[
    {
    Thick,
    ResourceFunction["SplineCircle"][{0, 0, 0}, {1,3}, {{0, 1, 0}, {0, 0, 1}}, {0, 3Pi/2}]
    },
    Boxed->False,
    AxesOrigin->{0,0,0},
    Axes->True,
    AxesEdge->{.5,.5,.5},
    AxesLabel->{x, y, z}
]

enter image description here

The syntax is ResourceFunction["SplineCircle"][center, {r1, r2}, {u, v}, angle] where r1 and r2 are the two axis lengths, and {u, v} defines the plane of the ellipse, with r1 in the direction u.

$\endgroup$
1
$\begingroup$

Another way to plot 3D ellipse would be

Scale[Cylinder[{{x, y, 0}, {x, y, 0.1}}, 1], {wx, wy, 1}]

where x, y gives the location and wx, wy give the length of major and minor axis.

$\endgroup$
0
$\begingroup$

I don't know if it's useful to anyone. As a mathematica newby, I was looking for a 'more intuitive' method of plotting 2D ellipses in 3D space. Here's my solution, for an ellipse with (axis of length a along unit vector ehatA) and (axis of length b along unit vector ehatB):

ellipsePoints[t_, position_, aEllipse_, bEllipse_, ehatA_, ehatB_] := position + aEllipse Cos[t] ehatA + bEllipse Sin[t] ehatB;

ellipse1[t_] := 
    kitePoints[t, positionTest, aEllipseTest, bEllipseTest, ehatATest, ehatBTest]

listEllipsePoints = Range[0, 2 Pi 100 ]/100;

ellipseGraph = Graphics3D[{Black, 
    Polygon[Map[ellipse1, listEllipsePoints]]
    }, AxesLabel -> {x, y, z}];
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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