How to Create 3D Torus from Circle Revolved about x=2r, r is the radius of circle (Python or JULIA)

Question:

I need help to create a torus out of a circle by revolving it about x=2r, r is the radius of the circle.

I am open to either JULIA code or Python code. Whichever that can solve my problem the most efficient.

I have Julia code to plot circle and the x=2r as the axis of revolution.

using Plots, LaTeXStrings, Plots.PlotMeasures
gr()

θ = 0:0.1:2.1π
x = 0 .+ 2cos.(θ)
y = 0 .+ 2sin.(θ)
plot(x, y, label=L"x^{2} + y^{2} = a^{2}",
    framestyle=:zerolines, legend=:outertop)

plot!([4], seriestype="vline", color=:green, label="x=2a")

1

I want to create a torus out of it, but unable, meanwhile I have solid of revolution Python code like this:

# Calculate the surface area of y = sqrt(r^2 - x^2)
# revolved about the x-axis

import matplotlib.pyplot as plt
import numpy as np
import sympy as sy

x = sy.Symbol("x", nonnegative=True)
r = sy.Symbol("r", nonnegative=True)

def f(x):
    return sy.sqrt(r**2 - x**2)

def fd(x):
    return sy.simplify(sy.diff(f(x), x))

def f2(x):
    return sy.sqrt((1 + (fd(x)**2)))

def vx(x):
    return 2*sy.pi*(f(x)*sy.sqrt(1 + (fd(x) ** 2)))
  
vxi = sy.Integral(vx(x), (x, -r, r))
vxf = vxi.simplify().doit()
vxn = vxf.evalf()

n = 100

fig = plt.figure(figsize=(14, 7))
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222, projection='3d')
ax3 = fig.add_subplot(223)
ax4 = fig.add_subplot(224, projection='3d')
# 1 is the starting point. The first 3 is the end point. 
# The last 200 is the number of discretization points. 
# help(np.linspace) to read its documentation. 
x = np.linspace(1, 3, 200)
# Plot the circle
y = np.sqrt(2 ** 2 - x ** 2)
t = np.linspace(0, np.pi * 2, n)

xn = np.outer(x, np.cos(t))
yn = np.outer(x, np.sin(t))
zn = np.zeros_like(xn)
for i in range(len(x)):
    zn[i:i + 1, :] = np.full_like(zn[0, :], y[i])

ax1.plot(x, y)
ax1.set_title("$f(x)$")
ax2.plot_surface(xn, yn, zn)
ax2.set_title("$f(x)$: Revolution around $y$")

# find the inverse of the function
y_inverse = x
x_inverse = np.power(2 ** 2 - y_inverse ** 2, 1 / 2)
xn_inverse = np.outer(x_inverse, np.cos(t))
yn_inverse = np.outer(x_inverse, np.sin(t))
zn_inverse = np.zeros_like(xn_inverse)
for i in range(len(x_inverse)):
    zn_inverse[i:i + 1, :] = np.full_like(zn_inverse[0, :], y_inverse[i])

ax3.plot(x_inverse, y_inverse)
ax3.set_title("Inverse of $f(x)$")
ax4.plot_surface(xn_inverse, yn_inverse, zn_inverse)
ax4.set_title("$f(x)$: Revolution around $x$ n Surface Area = {}".format(vxn))

plt.tight_layout()
plt.show()

2

Asked By: Freya the Goddess

||

Answers:

Here is a way that actually allows rotating any figure in the XY plane around the Y axis.

"""
Rotation of a figure in the XY plane about the Y axis:
    ϕ = angle of rotation
    z' = z * cos(ϕ) - x * sin(ϕ)
    x' = z * sin(ϕ) + x * cos(ϕ)
    y' = y
"""

using Plots

# OP definition of the circle, but we put center at x, y of 4, 0
#    for the torus, otherwise we get a bit of a sphere

θ = 0:0.1:2.1π 
x = 4 .+ 2cos.(θ)  # center at (s, 0, 0)
y = 0 .+ 2sin.(θ)
# add the original z values as 0
z = zeros(length(x))
plot(x, y, z, color=:red)

# add the rotation axis
ϕ = 0:0.1:π/2 # for full torus use 2π at stop of range
xprime, yprime, zprime = Float64[], Float64[], Float64[]

for a in ϕ, i in eachindex(θ)
    push!(zprime, z[i] + z[i] * cos(a) - x[i] * sin(a))
    push!(xprime, z[i] * sin(a) + x[i] * cos(a))
    push!(yprime, y[i])
end

plot!(xprime, yprime, zprime, alpha=0.3, color=:green)
Answered By: Bill

Here is a way using the Meshes package for the construction of the mesh and the MeshViz package for the visualization. You’ll just have to translate to fulfill your desiderata.

using Meshes
using MeshViz
using LinearAlgebra
using GLMakie


# revolution of the polygon defined by (x,y) around the z-axis
# x and y have the same length
function revolution(x, y, n)
  u_ = LinRange(0, 2*pi, n+1)[1:n]
  j_ = 1:(length(x) - 1)           # subtract 1 because of periodicity
  function f(u, j)
    return [x[j] * sin(u), x[j] * cos(u), y[j]]
  end
  points = [f(u, j) for u in u_ for j in j_]
  topo = GridTopology((length(j_), n), (true, true))
  return SimpleMesh(Meshes.Point.(points), topo)
end


# define the section to be rotated: a circle
R = 3 # major radius
r = 1 # minor radius
ntheta = 100
theta_ = LinRange(0, 2*pi, ntheta)
x = [R + r*cos(theta) for theta in theta_]
y = [r*sin(theta) for theta in theta_]

# make mesh
mesh = revolution(x, y, 100)
# visualize mesh
viz(mesh)

enter image description here


EDIT: animation

using Meshes
using MeshViz
using LinearAlgebra
using GLMakie
using Makie
using Printf

function revolutionTorus(R, r, alpha; n1=30, n2=90)
  theta_ = LinRange(0, 2, n1+1)[1:n1]
  x = [R + r*cospi(theta) for theta in theta_]
  y = [r*sinpi(theta) for theta in theta_]
  full = alpha == 2
  u_ = LinRange(0, alpha, n2 + full)[1:n2]
  function f(u, j)
    return [x[j] * sinpi(u), x[j] * cospi(u), y[j]]
  end
  points = [f(u, j) for u in u_ for j in 1:n1]
  topo = GridTopology((n1, n2 - !full), (true, full))
  return SimpleMesh(Meshes.Point.(points), topo)
end

# generates `nframes` meshes for alpha = 0 -> 2 (alpha is a multiple of pi)
R = 3
r = 1
nframes = 10
alpha_ = LinRange(0, 2, nframes+1)[2:(nframes+1)]
meshes = [revolutionTorus(R, r, alpha) for alpha in alpha_]

# draw and save the frames in a loop
for i in 1:nframes
  # make a bounding box in order that all frames have the same aspect
  fig, ax, plt = 
    viz(Meshes.Box(Meshes.Point(-4.5, -4.5, -2.5), Meshes.Point(4.5, 4.5, 2.5)); alpha = 0)
  ax.show_axis = false
  viz!(meshes[i])
  scale!(ax.scene, 1.8, 1.8, 1.8)
  png = @sprintf "revolutionTorus%02d.png" i
  Makie.save(png, fig)
end

# make GIF with ImageMagick
comm = @cmd "convert -delay 1x2 'revolutionTorus*.png' revolutionTorus.gif"
run(comm)

enter image description here

Answered By: Stéphane Laurent
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.