17

I would like to draw a sphere, of radius 3, and an ellipsoid of semi-axis 2, 3 and 4 together. They intersect at two great circles on the sphere (marked in red).

I started out with the sphere and the great circles:

\documentclass[border=2mm]{standalone}
\usepackage{tikz}
\usetikzlibrary{3dtools}% https://github.com/marmotghost/tikz-3dtools
\begin{document}
  \begin{tikzpicture}[3d/install view={phi=120,theta=70},line cap=butt,
       line join=round,declare function={R=3;},c/.style={circle,fill,inner sep=1pt}]
     \path (0,0,0) coordinate (O) ;
     \draw[blue,3d/screen coords] (O) circle[radius=R];
     \shade[ball color=white,3d/screen coords,opacity=0.7] (O) circle[radius=R];
%     \shade[ball color=blue!30,3d/screen coords,opacity=0.7,xscale=2,yscale=3,zscale=4] (O) circle[radius=1];
     \path pic[blue]{3d/circle on sphere={R=R,C={(O)}}};
     \path pic[red]{3d/circle on sphere={R=R, n={(0.592,0,-1)}}}; % plane x = sqrt{7/10) z
     \path pic[red]{3d/circle on sphere={R=R, n={(0.592,0,1)}}}; % plane x = sqrt{7/10) z
   \draw[3d/hidden] (0,0,0) -- (0,0,R)  (O)--(R,0,0) (O)--(0,R,0) (O)--(0,-R,0);
   \draw[3d/visible, -stealth] (R,0,0) -- (R + 4,0,0) node[below]{$x$};
   \draw[3d/visible, -stealth] (0,R,0) -- (0,R + 1,0) node[right]{$y$};
   \draw[3d/visible, -stealth] (0,0,R) -- (0,0,R + 1.5) node[above]{$z$};
\end{tikzpicture}
\end{document}

and everything is right so far:

sphere with intersecting great circles

but when I remove the comment on the line that I would expect to draw the ellipsoid

     \shade[ball color=blue!30,3d/screen coords,opacity=0.7,xscale=2,yscale=3,zscale=4] (O) circle[radius=1];

I get something that is far from what I expected, including the fact that the zscale is not understood.

enter image description here

How can one add the intersecting elipsoide to this image?

3
  • The key 3d/screen coords has already switched you from 3D to 2D. As a result, xscale and yscale scale the screen coordinates, while zscale has no meaning at all in this context. See page 8 of the 3D Tools manual. To get an answer to your question, you need to describe more precisely what you want to obtain. Commented yesterday
  • What I would like to obtain is an image of the sphere and ellipsoid together, with enough transparecy, that one could see both and the circles on intersection between the two which happens on the planes: x = +/- sqrt{7/20} x. Commented yesterday
  • You could experiment with transparencies in Desmos 3D screenshotted and pasted to MS Word, save the final result as an image, and input it with \includegraphics{} Commented yesterday

3 Answers 3

10

This is AI time! AI crosses various human languages and crosses different programming languages. It is helpful for both beginners and experts: saving a lot of code-writing time. Even we can ask AI to give a LaTeX file with detail calculations (see this overleaf link). You can ask AI for any language: Asymptote , POV-Ray, Python, manim, ...

Below are the code I ask Gemini Pro with minor modifications.

1. Manim Here is my first Manim on GanJingWorld.

manim 1st

2. Asymptote: simple and an improvement

simple Asymptote

better Asymptote

3. POV-Ray: This is nearly the first time I run POV-Ray; the code is mainly from AI, of course.

POV-Ray


Manim code:

from manim import *
import numpy as np

# Class must inherit from ThreeDScene
class SphereEllipsoidIntersection(ThreeDScene):
    def construct(self):
        # 1. Setup Camera and Axes
        self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES)
        axes = ThreeDAxes()
        # self.add(axes) # Optional: Uncomment to see axes

        # 2. Define Sphere (Radius = 3)
        # Using Parametric Surface for smooth rendering
        sphere = Surface(
            lambda u, v: np.array([
                3 * np.cos(u) * np.sin(v),
                3 * np.sin(u) * np.sin(v),
                3 * np.cos(v)
            ]),
            u_range=[0, 2 * PI],
            v_range=[0, PI],
            checkerboard_colors=[YELLOW_D, YELLOW_E],
            resolution=(24, 12), # Higher resolution = smoother
            fill_opacity=0.3
        )

        # 3. Define Ellipsoid (Semi-axes: 2, 3, 4)
        ellipsoid = Surface(
            lambda u, v: np.array([
                2 * np.cos(u) * np.sin(v),
                3 * np.sin(u) * np.sin(v),
                4 * np.cos(v)
            ]),
            u_range=[0, 2 * PI],
            v_range=[0, PI],
            checkerboard_colors=[BLUE_D, BLUE_E],
            resolution=(24, 12),
            fill_opacity=0.3
        )

        # 4. Define Intersection Curves (ParametricFunction)
        # x = sqrt(7/3)sin(t), y=3cos(t), z=+/- sqrt(20/3)sin(t)
        a = np.sqrt(7/3)
        b = np.sqrt(20/3)

        # Curve 1 (z > 0)
        curve1 = ParametricFunction(
            lambda t: np.array([
                a * np.sin(t),
                3 * np.cos(t),
                b * np.sin(t)
            ]),
            t_range=[0, 2 * PI],
            color=RED, stroke_width=6
        )

        # Curve 2 (z < 0)
        curve2 = ParametricFunction(
            lambda t: np.array([
                a * np.sin(t),
                3 * np.cos(t),
                -b * np.sin(t)
            ]),
            t_range=[0, 2 * PI],
            color=RED, stroke_width=6
        )

        # 5. Animation Sequence
        self.begin_ambient_camera_rotation(rate=0.1) # Slowly rotate camera
        
        # Draw Sphere
        self.play(Create(sphere), run_time=2)
        self.wait(0.5)
        
        # Draw Ellipsoid
        self.play(Create(ellipsoid), run_time=2)
        self.wait(0.5)
        
        # Trace Intersection Curves
        self.play(Create(curve1), Create(curve2), run_time=3)
        
        self.wait(3)

# --- THONNY RUNNER CONFIGURATION ---
if __name__ == "__main__":
    from manim import config
    
    # Configure output settings specifically for direct run
    config.media_width = "75%"
    config.verbosity = "WARNING"
    config.preview = True      # Automatically open the video file
    config.quality = "high_quality" # Use "medium_quality" or "high_quality" for final render
    
    # Run the scene
    scene = SphereEllipsoidIntersection()
    scene.render()

The first Asymptote code:

// https://asymptote.ualberta.ca/
import solids;
import graph3;
settings.render=8; //  anti-aliasing (ví dụ: 8, 16)
settings.prc=false; // usually improve image's quality
size(300);
currentprojection=orthographic(5,4,2);

// the sphere
draw(scale3(3)*unitsphere, yellow+opacity(.2));

// Ellipsoid 
draw(scale(2,3,4)*unitsphere, blue+opacity(.2));

// intersections
real a = sqrt(7/3);
real b = sqrt(20/3);

path3 p1 = graph(new triple(real t) {
  return (a*sin(t), 3*cos(t), b*sin(t));
}, 0, 2*pi, operator ..);

path3 p2 = graph(new triple(real t) {
  return (a*sin(t), 3*cos(t), -b*sin(t));
}, 0, 2*pi, operator ..);

draw(p1, red+linewidth(2));
draw(p2, red+linewidth(2));

The second Asymptote code: for anti-aliasing.

// https://asymptote.ualberta.ca/
import solids;
import graph3;

// HIGH QUALITY RENDER SETTINGS
settings.render = 16;  // Increase anti-aliasing level (higher is smoother but slower)
settings.prc = false;  // Disable PRC to focus on high-quality raster/vector image
size(300);

// Lighting: Adds depth and shine to 3D objects
currentlight = light(white, (5, 5, 10), specularfactor=3.0);
currentprojection = orthographic(5, 4, 2);

// 1. DEFINE PARAMETRIC FUNCTIONS FOR SPHERE AND ELLIPSOID
// This allows better control over mesh smoothness compared to the built-in unitsphere

// Sphere with radius 3
triple sphere_param(pair p) {
  real u = p.x;
  real v = p.y;
  return (3*cos(u)*sin(v), 3*sin(u)*sin(v), 3*cos(v));
}

// Ellipsoid with semi-axes (2, 3, 4)
triple ellipsoid_param(pair p) {
  real u = p.x;
  real v = p.y;
  return (2*cos(u)*sin(v), 3*sin(u)*sin(v), 4*cos(v));
}

// 2. DRAW SURFACES WITH HIGH RESOLUTION
// nu=60, nv=30: Increase mesh count for an extremely smooth surface (removes jagged edges)
surface s_sphere = surface(sphere_param, (0,0), (2*pi, pi), 60, 30, Spline);
surface s_ellipsoid = surface(ellipsoid_param, (0,0), (2*pi, pi), 60, 30, Spline);

// Draw with material: adds shininess and transparency
// Opacity should be < 1 to see internal intersections and create a "glass" effect
draw(s_sphere, material(yellow + opacity(1), shininess=0.5));
draw(s_ellipsoid, material(blue + opacity(1), shininess=0.5));

// 3. DRAW SMOOTH INTERSECTION CURVES
real a = sqrt(7/3);
real b = sqrt(20/3);

// Increase sample points (n=200) for smoother curves
path3 p1 = graph(new triple(real t) {
  return (a*sin(t), 3*cos(t), b*sin(t));
}, 0, 2*pi, n=200, operator ..);

path3 p2 = graph(new triple(real t) {
  return (a*sin(t), 3*cos(t), -b*sin(t));
}, 0, 2*pi, n=200, operator ..);

// Draw thicker intersection lines
draw(p1, red + linewidth(2.5));
draw(p2, red + linewidth(2.5));

POV-Ray code

#version 3.7;
#include "colors.inc"
#include "textures.inc"

global_settings { assumed_gamma 1.0 }

// --- NEW SETTING: Background Color ---
//background { color White } // Change to White (default is Black)

// 1. Camera Settings
camera {
  // Moved closer to <0,0,0> to reduce empty space (Zoom in)
  location <2, 8, 3> 
  look_at  <0, 0, 0>   // Look at origin
  right x*image_width/image_height
}

// 2. Light Sources
light_source { <10, 10, -10> color White }
light_source { <-10, 5, -5>  color White shadowless} // Fill light

// 3. Material Definitions (Transparent Glass)
#declare MatSphere = texture {
    // Adjusted filter to 0.8 for real 80% transparency
    pigment { color Yellow filter 0.8 } 
    finish { phong 1 reflection 0.2 } // Reduced reflection slightly for white background
}

#declare MatEllipsoid = texture {
    pigment { color Blue filter 0.8 }
    finish { phong 1 reflection 0.2 }
}

// 4. Draw Sphere (R=3)
sphere {
  <0, 0, 0>, 1
  scale <3, 3, 3>
  texture { MatSphere }
}

// 5. Draw Ellipsoid (2, 3, 4)
sphere {
  <0, 0, 0>, 1
  scale <2, 3, 4>
  texture { MatEllipsoid }
}

// 6. Draw Intersection Curves (Parametric Curves)
// Parameters from the problem: 
// x = sqrt(7/3)*sin(t)
// y = 3*cos(t)
// z = +/- sqrt(20/3)*sin(t)

#declare A = sqrt(7/3);
#declare B = sqrt(20/3);
#declare LineRadius = 0.04; // Slightly thicker for better visibility

#declare Step = 0.002; // Smaller step for smoother curves
#declare T = 0;

union {
    #while (T < 2*pi)
        // Current point coordinates
        #local Px = A * sin(T);
        #local Py = 3 * cos(T);
        #local Pz = B * sin(T);
        
        // Draw point (small sphere) at curve 1 (positive Z)
        sphere { <Px, Py, Pz>, LineRadius pigment { Red } }
        
        // Draw point at curve 2 (negative Z)
        sphere { <Px, Py, -Pz>, LineRadius pigment { Red } }
        
        #declare T = T + Step;
    #end
    no_shadow // No shadow casting for cleaner look
}
5
  • 1
    I concur with you about the AI. Commented yesterday
  • 1
    It is pretty hard to beat PovRay, especially with all the choices on how to color the surface that are not available on the others. Very nice. Commented yesterday
  • I have just added a manim link on GJW ganjingworld.com/s/eZQeJxzwQz Commented 17 hours ago
  • 1
    For the sake of completeness, could you add the Manim code used? Commented 12 hours ago
  • 1
    @projetmbc Sure! I added. Commented 11 hours ago
14

Here is a proposal with luadraw:

\documentclass[border=5pt]{standalone}% compile with lualatex only
\usepackage[svgnames]{xcolor}
\usepackage[3d]{luadraw}%https://github.com/pfradin/luadraw
\usepackage{fourier-otf}
%https://tex.stackexchange.com/questions/755898/drawing-a-sphere-and-ellipsoid-together
\begin{document}
\begin{luadraw}{name=sphere_ellipsoid1}
local g = graph3d:new{viewdir={100,80},bbox=false, bg="lightgray"}
local S = sphere(Origin, 3, 30,30)
local a = math.sqrt(7/20)
local P1 = {Origin, M(1,0,a)}
local P2 = {Origin, M(1,0,-a)} -- planes to cut the sphere
local S1, S2 = cutfacet(S,P1)
S1 = cutfacet(S1,P2)
S2 = cutfacet(S2,{Origin,-P2[2]})
S1 = g:Classifyfacet(S1) -- only visible facets
S2 = g:Classifyfacet(S2)
local B1, B2 = border(S1), border(S2)
local b1, b2 = g:Proj3d(B1)[1], g:Proj3d(B2)[1]
table.insert(b2,2,"m")
local chem = concat(b1,"l",b2,"l") -- Outline of the visible part of the sphere
-- drawing
g:Savematrix()
g:Setmatrix3d( {Origin, 2*vecI, 3*vecJ, 4*vecK} )
g:Dsphere(Origin,1,{color="Crimson", mode=mBorder}) -- ellipsoid
g:Restorematrix()
g:Beginclip(chem)
g:Dsphere(Origin, 3,{color = "Orange",mode=mBorder}) --to get the correct shading
g:Endclip()
g:Dpath(chem)
g:Dpolyline3d({{3*vecI,4*vecI},{3*vecJ,6*vecJ},{4*vecK,5*vecK}}, "line width=0.8pt,-stealth")
g:Dlabel3d("$x$", 4*vecI,{pos="W"}, "$y$",6*vecJ,{pos="S"}, "$z$",5*vecK,{pos="N"})
-- hidden part
g:Dpolyline3d({{Origin,4*vecI},{Origin,6*vecJ},{Origin,5*vecK}}, "dashed")
g:Linestyle("dotted")
g:Dsphere(Origin,2.99,{mode=mBorder})
g:Dcircle3d(Origin,3,P1[2]); g:Dcircle3d(Origin,3,P2[2]) -- intersection
g:Savematrix(); g:Setmatrix3d( {Origin, 2*vecI, 3*vecJ, 4*vecK} )
g:Dsphere(Origin,1,{mode=mBorder})
g:Restorematrix()
g:Show()
\end{luadraw}
\end{document}

enter image description here

EDIT Here is another approach that should allow us to change our perspectives.

\documentclass[border=5pt]{standalone}% compile with lualatex only
\usepackage[svgnames]{xcolor}
\usepackage[3d]{luadraw}%https://github.com/pfradin/luadraw
\usepackage{fourier-otf}
%https://tex.stackexchange.com/questions/755898/drawing-a-sphere-and-ellipsoid-together
\begin{document}

\begin{luadraw}{name=sphere_ellipsoid3}
local cos, sin, pi = math.cos, math.sin, math.pi
local g = graph3d:new{viewdir={40,70},bbox=false, bg="lightgray"}
require 'luadraw_spherical'
Hiddenlines = true; Hiddenlinestyle = "dotted"
g:Linewidth(8)
local a = math.sqrt(7/20)
local n1, n2 = pt3d.normalize(M(1,0,a)), pt3d.normalize(M(1,0,-a))
local p = function(u,v) return M(2*cos(u)*sin(v),3*sin(u)*sin(v),4*cos(v)) end
local ellipsoid = surface(p,-pi,pi,0,pi,{30,30})
ellipsoid = g:Sortfacet(ellipsoid)

g:Define_sphere( {center=Origin, radius=3, color="Orange"})
g:DScircle({Origin, n1}, {color="ForestGreen"})
g:DScircle({Origin, n2}, {color="ForestGreen"})
g:DSpolyline(facetedges(ellipsoid), {hidden=false, color="Crimson",width=6})
g:DSpolyline({{-4*vecI,4*vecI},{-4*vecJ,4*vecJ},{-5*vecK,5*vecK}}, {arrows=1})
g:DSlabel("$x$", 4.25*vecI,{}, "$y$",4.25*vecJ,{}, "$z$",5*vecK,{pos="N"})
g:Linestyle("noline"); g:Dspherical(); g:Lineoptions("dotted","Crimson",8)
--g:Dlabel3d("$x$", 4*vecI,{pos="W"}, "$y$",4*vecJ,{pos="W"}, "$z$",5*vecK,{pos="N"})
g:Savematrix(); g:Setmatrix3d( {Origin, 2*vecI, 3*vecJ, 4*vecK} )
g:Dsphere(Origin,1,{mode=mBorder})
g:Restorematrix()
g:Show()
\end{luadraw}
\end{document}

enter image description here

4
  • 1
    This doesn't look right; the "sphere" has two maxima of illumination. Commented yesterday
  • 1
    @Mike I've edited my answer to get the correct shading. Commented yesterday
  • @nidarfp Very nice image and package. If you allow me, I have a few questions: 1- Does one have access to the underneath TikZ code generated? How can one change the thickness of the lines (continuous and dotted) ? When you move it inyo certain directions (example being: viewdir={100,80}) it develops a few artifacts, like the sphere looses smoothness a bit and the one of the intersection curves go over the intersection point. Is there a way to improve these points? Commented yesterday
  • @Knudsen 1) The TikZ code is saved in a file named <name>.tkz in the _luadraw subfolder. 2) You can change the line style globally (using the Lineoptions() method) or locally using the draw_options option. You will find more details on these two points in the documentation. Regarding point 3, for this drawing (which is actually a 2D drawing), I only considered the horizon line of the sphere and not that of the ellipsoid. Both should be considered to avoid artifacts depending on the viewing angle. I will edit my answer to add another approach. Commented 15 hours ago
12

If we restrict ourselves to the 3dtools package alone, we can obtain a result along the lines of what is shown in the figure.
Note that in your code the wrong planes are specified in tikz-3dtools: the normal vector is given as (k,0,-1) instead of the correct (1,0,-k).

\documentclass[border=5mm]{standalone}
\usepackage{tikz}
\usetikzlibrary{3dtools}% https://github.com/marmotghost/tikz-3dtools  

\begin{document}
\begin{tikzpicture}[
  3d/install view={phi=120,theta=70},
  line cap=butt,
  line join=round,
  declare function={
    R=3;       % sphere radius
    a=2; b=3; c=4; % ellipsoid semi-axes
  },
  c/.style={circle,fill,inner sep=1pt}
]

  \path (0,0,0) coordinate (O);

  %------------------------------------------------
  % SPHERE
  %------------------------------------------------
  \draw[blue,3d/screen coords] (O) circle[radius=R];
  \shade[ball color=white,3d/screen coords,opacity=0.4] (O) circle[radius=R];

  % "equator" of the sphere (if needed)
  \path pic[blue]{3d/circle on sphere={R=R,C={(O)}}};

  %------------------------------------------------
  % ELLIPSOID x^2/4 + y^2/9 + z^2/16 = 1 (a=2, b=3, c=4)
  % Parametrization:
  %   x = a cos u cos v
  %   y = b cos u sin v
  %   z = c sin u
  % u — latitude (−90..90), v — longitude (0..360)
  %------------------------------------------------

  % Parallels (u = const)
  \foreach \u in {-90,-85,...,90} {%
    \draw[orange!80!black,opacity=0.4]
      plot[domain=-60:110,samples=60]
        ({a*cos(\u)*cos(\x)},
         {b*cos(\u)*sin(\x)},
         {c*sin(\u)});
  }

  % Meridians (v = const)
  \foreach \v in {105,110,...,295} {%
    \draw[orange!80!black,opacity=0.4]
      plot[domain=-90:90,samples=60] % slightly short of the poles to avoid clustering
        ({a*cos(\x)*cos(\v)},
         {b*cos(\x)*sin(\v)},
         {c*sin(\x)});
  }

  %------------------------------------------------
  % INTERSECTION CIRCLES (planes x = ± sqrt(7/20) z)
  %------------------------------------------------
    \pgfmathsetmacro{\kappa}{sqrt(7/20)}
    \path pic[ultra thick,red]{3d/circle on sphere={R=R,C={(O)}, n={(1,0,-\kappa)}}};
    \path pic[ultra thick,red]{3d/circle on sphere={R=R,C={(O)}, n={(1,0, \kappa)}}};

  %------------------------------------------------
  % AXES
  %------------------------------------------------
  \draw[3d/hidden]  (O)--(0,0,R)  (O)--(R,0,0) (O)--(0,R,0) (O)--(0,-R,0);
  \draw[3d/visible, -stealth] (R,0,0) -- (R + 4,0,0) node[below]{$x$};
  \draw[3d/visible, -stealth] (0,R,0) -- (0,R + 1,0) node[right]{$y$};
  \draw[3d/visible, -stealth] (0,0,R) -- (0,0,R + 1.5) node[above]{$z$};

\end{tikzpicture}
\end{document}

enter image description here

1
  • Very nice, I did not know I was beating in a dead horse and that 3dtools was NOT able to draw an ellipsoide. Commented yesterday

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.