# How to draw an ellipse arc in 3D?

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}}]]


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 ?

-
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. –  Guess who it is. Jun 7 '12 at 16:05
What would your preferred input for your arc be? There are many ways to parametrize... –  Yves Klett Jun 7 '12 at 17:20
@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. –  ogerard Jun 8 '12 at 5:29
Highly relevant: mathematica.stackexchange.com/questions/10957/… –  Sjoerd C. de Vries Sep 14 '13 at 7:10

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]}]


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).

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

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[],
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}
}
}
]
}]


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]


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}}
]
}]


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]
]
}]


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:

-

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}}]


-
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? –  ogerard Jun 8 '12 at 5:32

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.

-

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.

-