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")
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()
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)
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)
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)
Assuming that an object is moving vertically downwards as well along Y-axis at a velocity of lets say 0.5 m/s while following the elliptical equation,
major axis radius = 100
minor axis radius = 25
Body's initial position can be assumed to be at (x,y) = (175, 150). Ellipse Image
I know how to fetch co-ordinates o ellipse when it is not moving downwards.
a = 25
b = 100
h = 150
k = 150
$ x = \sqrt{a^2 - {(y-k)^2 * a^2 \over b^2} } + h $
$ x = \sqrt{25^2 - {(y-150)^2 * 25^2 \over 100^2} } + 150 $
# Python code:
t = np.linspace(0,360,360)
x = 150 + 25*np.cos(np.radians(t)) # 150 is major axis of ellipse
y = 150 + 100*np.sin(np.radians(t)) # 150 is minor axis of ellipse
# plt.plot(x,y)
# plt.show()
df = pd.DataFrame(list(zip(x, y)), columns = ['x', 'y'])
# remove duplicate rows
df = df.drop_duplicates(keep = 'first')
ax = sns.scatterplot(data = df, x = 'x', y = 'y')
ax.set_xlim(0, 400)
ax.set_ylim(0, 300)
plt.grid()
def solve_for_x(y):
a = 25
b = 100
h = 150
k = 150
x1 = math.sqrt(a**2 - ( ( (y-k)**2 * a**2 )/b**2 )) + h
x2 = - math.sqrt(a**2 - ( ( (y-k)**2 * a**2 )/b**2 )) + h
# print(f'x = {x}')
return x1, x2
This code will return both sides of ellipse.
But my question is how to calculate x and y co-ordinates when the body is moving downwards. I imagine the path traced will be a weird 2d spring like structure.
You have to define the angular speed of a point on your ellipse, and from that you can determine a new np.linspace array that will represent time. Then you can simply substract 1/2*g*time**2 from your y array to get the y-coordinates of points on the falling ellipse.
I added a colormap to represent the time too.
# Imports.
import matplotlib.pyplot as plt
import numpy as np
# Constants.
G = 9.81
ANGULAR_SPEED = 60 # °/s
SPINS = 2.5
POINTS = 10000
# "Physics!"
angle = np.linspace(0, 360*SPINS, POINTS)
x = 150 + 25*np.cos(np.radians(angle))
ys = 150 + 100*np.sin(np.radians(angle)) # Static.
time = angle/ANGULAR_SPEED
yf = ys - 1/2*G*time**2
# Show the result.
fig, ax = plt.subplots()
# ax.set_aspect(1) # Optional: so that autoscaling doesn't squish our ellipse into a circle.
ax.scatter(x, ys, label="static ellipse")
ax.scatter(x, yf, label="falling ellipse", c=time, cmap="autumn")
ax.legend()
fig.show()
If you want to stick to a constant downward velocity, it's possible too:
# Constants.
...
VY = -200
...
# "Physics!"
...
yf = ys + VY*time
...
desired output**I'm trying to implement periodic condition for horizontal direction, I discretized laplace equation bottom temperature is high, at the top temperature is zero and also left and right side **
import numpy as np
import matplotlib.pyplot as plt
# Set maximum iteration
maxIter = 500
lenX = lenY = 20 #we set it rectangular
delta = 1
# Boundary condition
Ttop = 0
Tbottom = 9.75
Tright = 0
Tleft = 0
# Initial guess of interior grid
Tguess = (Ttop + Tbottom)/2
colorinterpolation = 50
colourMap = plt.cm.jet #you can try: colourMap = plt.cm.coolwarm
X, Y = np.meshgrid(np.arange(0, lenX), np.arange(0, lenY))#,indexing='ij')
T = np.empty((lenX, lenY))+ np.random.random((lenX,lenY))
T.fill(Tguess)
T[(lenY-1):, :] = Ttop
T[:1, :] = Tbottom
T[:, (lenX-1):] = Tright
T[:, :1] = Tleft
for iteration in range(0, maxIter):
for i in range(1, lenX-1, delta):
for j in range(1, lenY-1, delta):
T[i, j] = 0.125 * (T[i+1][j] + T[i-1][j] + T[i][j+1] + T[i][j-1] - 4*T[i,j]) + T[i,j]
plt.contourf(X, Y, T, colorinterpolation, cmap=colourMap)
plt.colorbar()
plt.show()
I'm getting this
The code outputs a graph that is nowhere near what you'd expect of a projectile motion type of graph. In addition, if you change the step number to around 2, the graph doesn't output much of anything.
import numpy as np
import matplotlib.pyplot as plt
grav = 9.8
airDen = 1.225 # kg/m^3
areaProj = 0.8643 # m^2
v0 = 198.1 # m/s
angle = 60.0
dragCoef = 0.62 #Approximate value
mass = 15.0 #kg
step = 0.02 #time step in seconds
t = [0]
vx = [v0*np.cos(angle*np.pi/180)]
vy = [v0*np.sin(angle*np.pi/180)]
x = [0]
y = [0]
dragForce = 0.5*dragCoef*areaProj*(v0**2)*airDen
ax = [-(dragForce*np.cos(angle/180*np.pi))/mass]
ay = [-grav-(dragForce*np.sin(angle/180*np.pi)/mass)]
counter = 0
while(y[counter] >= 0):
t.append(t[counter]+step)
vx.append(vx[counter]+step*ax[counter])
vy.append(vy[counter]+step*ay[counter])
x.append(x[counter]+step*vx[counter])
y.append(y[counter]+step*vy[counter])
vel = np.sqrt(vx[counter+1]**2 + vy[counter+1]**2)
dragForce = 0.5*dragCoef*areaProj*(vel**2)*airDen
ax.append(-(dragForce*np.cos(angle/180*np.pi))/mass)
ay.append(-grav-(dragForce*np.sin(angle/180*np.pi)/mass))
counter=counter+1
plt.plot(x,y)
plt.ylabel("y (m)")
plt.xlabel("x (m)")
Graph-example
Looks like you're not updating your angle, so instead of reaching zero vx it accelerates backwards since it thinks you're still going at 60 degrees initial angle. Adding an updated angle based on the current velocity vector results in the following:
import numpy as np
import matplotlib.pyplot as plt
grav = 9.8
airDen = 1.225 # kg/m^3
areaProj = 0.8643 # m^2
v0 = 198.1 # m/s
angle = 60.0
dragCoef = 0.62 #Approximate value
mass = 15.0 #kg
step = 0.02 #time step in seconds
t = [0]
vx = [v0*np.cos(angle*np.pi/180)]
vy = [v0*np.sin(angle*np.pi/180)]
x = [0]
y = [0]
dragForce = 0.5*dragCoef*areaProj*(v0**2)*airDen
ax = [-(dragForce*np.cos(angle/180*np.pi))/mass]
ay = [-grav-(dragForce*np.sin(angle/180*np.pi)/mass)]
counter = 0
while(y[counter] >= 0):
t.append(t[counter]+step)
vx.append(vx[counter]+step*ax[counter])
vy.append(vy[counter]+step*ay[counter])
x.append(x[counter]+step*vx[counter])
y.append(y[counter]+step*vy[counter])
vel = np.sqrt(vx[counter+1]**2 + vy[counter+1]**2)
dragForce = 0.5*dragCoef*areaProj*(vel**2)*airDen
angle = np.arctan(vy[counter]/vx[counter]) * (180 / np.pi)
ax.append(-(dragForce*np.cos(angle/180*np.pi))/mass)
ay.append(-grav-(dragForce*np.sin(angle/180*np.pi)/mass))
counter=counter+1
plt.plot(x,y)
plt.ylabel("y (m)")
plt.xlabel("x (m)")
I am using the below codes to plot a line with two slopes as shown in the picture.The slope should should decline after certain limit [limit=5]. I am using vectorisation method to set the slope values.Is there any other method to set the slope values.Could anyone help me in this?
import matplotlib.pyplot as plt
import numpy as np
#Setting the condition
L=5 #Limit
m=1 #Slope
c=0 #Intercept
x=np.linspace(0,10,1000)
#Calculate the y value
y=m*x+c
#plot the line
plt.plot(x,y)
#Set the slope values using vectorisation
m[(x<L)] = 1.0
m[(x>L)] = 0.75
# plot the line again
plt.plot(x,y)
#Display with grids
plt.grid()
plt.show()
You may be overthinking the problem. There are two line segments in the picture:
From (0, 0) to (A, A')
From (A, A') to (B, B')
You know that A = 5, m = 1, so A' = 5. You also know that B = 10. Given that (B' - A') / (B - A) = 0.75, we have B' = 8.75. You can therefore make the plot as follows:
from matplotlib import pyplot as plt
m0 = 1
m1 = 0.75
x0 = 0 # Intercept
x1 = 5 # A
x2 = 10 # B
y0 = 0 # Intercept
y1 = y0 + m0 * (x1 - x0) # A'
y2 = y1 + m1 * (x2 - x1) # B'
plt.plot([x0, x1, x2], [y0, y1, y2])
Hopefully you see the pattern for computing y values for a given set of limits. Here is the result:
Now let's say you really did want to use vectorization for some obscure reason. You would want to compute all the y values up front and plot once, otherwise you will get weird results. Here are some modifications to your original code:
from matplotlib import pyplot as plt
import numpy as np
#Setting the condition
L = 5 #Limit
x = np.linspace(0, 10, 1000)
lMask = (x<=L) # Avoid recomputing this mask
# Compute a vector of slope values for each x
m = np.zeros_like(x)
m[lMask] = 1.0
m[~lMask] = 0.75
# Compute the y-intercept for each segment
b = np.zeros_like(x)
#b[lMask] = 0.0 # Already set to zero, so skip this step
b[~lMask] = L * (m[0] - 0.75)
# Compute the y-vector
y = m * x + b
# plot the line again
plt.plot(x, y)
#Display with grids
plt.grid()
plt.show()
Following your code, you should modify the main part like this:
x=np.linspace(0,10,1000)
m = np.empty(x.shape)
c = np.empty(x.shape)
m[(x<L)] = 1.0
c[x<L] = 0
m[(x>L)] = 0.75
c[x>L] = L*(1.0 - 0.75)
y=m*x+c
plt.plot(x,y)
Note that c needs to change as well for the line to be continuous. This is the result: