如何从圆创建 3D 圆环 围绕 x=2r 旋转,r 是圆的半径(Python 或 JULIA)

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

提问人:Freya the Goddess 提问时间:2/11/2023 更新时间:6/4/2023 访问量:236

问:

我需要帮助通过围绕 x=2r 旋转圆圈来创建一个圆环,r 是圆的半径。

我对 JULIA 代码或 Python 代码持开放态度。无论哪种方法可以最有效地解决我的问题。

我有 Julia 代码来绘制圆,并将 x=2r 作为公转轴。

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

我想用它创建一个环面,但无法,同时我有像这样的革命性 Python 代码:

# 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

蟒蛇 朱莉娅

评论


答:

3赞 Bill 2/13/2023 #1

这是一种实际上允许围绕 Y 轴旋转 XY 平面中任何图形的方法。

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

评论

0赞 Freya the Goddess 2/14/2023
我们可以用它制作动画,从圆形变成完整的圆环吗?
0赞 Bill 2/15/2023
请参阅上文,或者您可以使用此修改:for a in φ for i in eachindex(θ) push!(zprime, z[i] + z[i] * cos(a) - x[i] * sin(a)) 推!(xprime, z[i] * sin(a) + x[i] * cos(a)) 推!(yprime, y[i]) 结束 p = 剧情!(xprime, yprime, zprime, color = :green, legend = false) display(p) 空!(xprime) 空了!(yprime)空的!(zprime) sleep(0.2) 结束 end
1赞 Stéphane Laurent 2/14/2023 #2

这是一种使用 Meshes 包构建网格和使用 MeshViz 包进行可视化的方法。你只需要翻译来完成你的任务。

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


编辑:动画

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

评论

0赞 Freya the Goddess 2/14/2023
如何使用GLMakie制作动画,从单圆变成完整的圆环,如上图所示?
0赞 Stéphane Laurent 2/14/2023
@FreyatheGoddess 一种可能的方法是在函数中用从 到 的角度进行替换,对每个获得的图像进行 png 并将图像挂载到 GIF 中?2*pi02*pi
0赞 Freya the Goddess 2/14/2023
好吧,那我就试着做动画了。听起来很有趣
0赞 Stéphane Laurent 2/15/2023
@FreyatheGoddess我做了一个动画。请看我的编辑。
0赞 Freya the Goddess 2/15/2023
哇,真是太神奇了!非常感谢,我家里有很多布丁,如果你来的话可以吃一些
1赞 dcarrot 6/4/2023 #3

我对 Makie 的看法:

using GLMakie

Base.@kwdef mutable struct Torus
    R::Float64 = 2
    r::Float64 = 1
end

function generate_torus(torus::Torus, resolution=100; upto=1.0)
    u = range(0, stop=2π*upto, length=resolution) 
    v = range(0, stop=2π*upto, length=resolution) 
    x = [ ( torus.R + torus.r*cos(vᵢ) ) * cos(uᵢ) for vᵢ in v, uᵢ in u ]
    y = [ ( torus.R + torus.r*cos(vᵢ) ) * sin(uᵢ) for vᵢ in v, uᵢ in u ]
    z = [ torus.r * sin(vᵢ) for vᵢ in v, _ in u ]
    return x, y, z
end

function animate_torus(torus::Torus, filename="torus.gif")
    fig = Figure(resolution = (500, 500))
    ax = fig[1, 1] = LScene(fig)
    cam3d!(ax.scene)

    # Initialize surface plot with full torus
    x, y, z = generate_torus(torus)
    p = surface!(ax, x, y, z, colormap=:viridis, shading = false)
    # Set the limits
    xlims!(ax.scene, (-4, 4))
    ylims!(ax.scene, (-4, 4))
    zlims!(ax.scene, (-1, 1))

    record(fig, filename, range(0, stop=1, length=100)) do i
        # Update data of surface plot
        x, y, z = generate_torus(torus, upto=i)
        p[1] = x
        p[2] = y
        p[3] = z
    end
end

Torus with Makie和情节

using Plots

Base.@kwdef mutable struct Torus
    x::Float64 = cos(0) + cos(0)*cos(0)
    y::Float64 = sin(0) + cos(0)*sin(0)
    z::Float64 = sin(0)
 end

function step!(torus::Torus, t, u; r=1)
    torus.x = r*cos(t) + cos(u)*cos(t)
    torus.y = r*sin(t) + cos(u)*sin(t)
    torus.z = sin(u)
    return torus
end

torus = Torus()
plt = plot([0], [0], [0], aspect_ratio=:equal, xlims=(-3, 3), ylims=(-3, 3), zlims=(-3, 3))
@gif for t in range(0, stop=2π, length=100)
     for u in range(0, stop=2π, length=100)
         step!(torus, t, u, r=2)
         push!(plt, torus.x, torus.y, torus.z)
     end
end every 2

enter image description here

评论

0赞 Freya the Goddess 6/6/2023
哇,太棒了,谢谢你的两个解决方案。您是真正的朱莉娅动画专家。
0赞 Freya the Goddess 6/6/2023
我想问一下,得到这个后该怎么办:我尝试了,记录没有保存在任何地方animate_torus (generic function with 2 methods)animate_torus()
1赞 dcarrot 6/7/2023
你通过了圆环吗?像这样实例化一个环面,并将其传递给调用,并保存它:torus = Torus()animate_torusanimate_torus(torus, "yourpath/name.gif")
0赞 Freya the Goddess 6/11/2023
是的,我在您的 GLMakie 代码之后调用它: ,然后是这个: 但是得到错误:torus = Torus()animate_torus(torus,"home/newtorus.gif")MethodError: no method matching xlims!(::Scene, ::Tuple{Int64, Int64})