How to get axis ground in mayavi - python

As there are many questions (this, this and this) about axis grid in mayavi that how to get matplotlib type grid using mayavi and there is no satisfactory answer even from Mayavi updates.
So regarding above problem, there is an idea that we can add ground plane in Mayavi as object and then we can draw/show required objects on ground plane. Below is object that I draw as ground plane
Code for above draw ground is
x, y = np.mgrid[-10:10:200j, -10:10:200j]
z = np.sin(x * y) / (x * y)
mlab.figure(bgcolor=(1, 1, 1))
mlab.surf(z, colormap='cool')
mlab.show()
Let's say we have an object that we want to draw/show it on above ground plane.
Below is object (as a example)
Code for above object is
mlab.figure(fgcolor=(0, 0, 0), bgcolor=(1, 1, 1))
u, v = mgrid[- 0.035:pi:0.01, - 0.035:pi:0.01]
X = 2 / 3. * (cos(u) * cos(2 * v) + sqrt(2) * sin(u) * cos(v)) * cos(u) / (sqrt(2) - sin(2 * u) * sin(3 * v))
Y = 2 / 3. * (cos(u) * sin(2 * v) - sqrt(2) * sin(u) * sin(v)) * cos(u) / (sqrt(2) - sin(2 * u) * sin(3 * v))
Z = -sqrt(2) * cos(u) * cos(u) / (sqrt(2) - sin(2 * u) * sin(3 * v))
S = sin(u)
mlab.mesh(X, Y, Z, scalars=S, colormap='YlGnBu', )
mlab.view(.0, - 5.0, 4)
mlab.show()
This code is available here
So how we can draw given object on the given ground plane same like below image? I edit this image in photoshop for better view.
Looking for some kind suggestions.

Related

Vedo 3D-Gyroid structures STL export

I need to generate a double 3D gyroid structure. For this, I'm using vedo
from matplotlib import pyplot as plt
from scipy.constants import speed_of_light
from vedo import *
import numpy as np
# Paramters
a = 5
length = 100
width = 100
height = 10
pi = np.pi
x, y, z = np.mgrid[:length, :width, :height]
def gen_strut(start, stop):
'''Generate the strut parameter t for the gyroid surface. Create a linear gradient'''
strut_param = np.ones((length, 1))
strut_param = strut_param * np.linspace(start, stop, width)
t = np.repeat(strut_param[:, :, np.newaxis], height, axis=2)
return t
plt = Plotter(shape=(1, 1), interactive=False, axes=3)
scale=0.5
cox = cos(scale * pi * x / a)
siy = sin(scale * pi * y / a)
coy = cos(scale * pi * y / a)
siz = sin(scale * pi * z / a)
coz = cos(scale * pi * z / a)
six = sin(scale * pi * x / a)
U1 = ((six ** 2) * (coy ** 2) +
(siy ** 2) * (coz ** 2) +
(siz ** 2) * (cox ** 2) +
(2 * six * coy * siy * coz) +
(2 * six * coy * siz * cox) +
(2 * cox * siy * siz * coz)) - (gen_strut(0, 1.3) ** 2)
threshold = 0
iso1 = Volume(U1).isosurface(threshold).c('silver').alpha(1)
cube = TessellatedBox(n=(int(length-1), int(width-1), int(height-1)), spacing=(1, 1, 1))
iso_cut = cube.cutWithMesh(iso1).c('silver').alpha(1)
# Combine the two meshes into a single mesh
plt.at(0).show([cube, iso1], "Double Gyroid 1", resetcam=False)
plt.interactive().close()
The result looks quite good, but now I'm struggling with exporting the volume. Although vedo has over 300 examples, I did not find anything in the documentation to export this as a watertight volume for 3D-Printing. How can I achieve this?
I assume you mean that you want to extract a watertight mesh as an STL (?).
This is a non trivial problem because it is only well defined on a subset of the mesh regions where the in/out is not ambiguous, in those cases fill_holes() seems to do a decent job..
Other cases should be dealt "manually". Eg, you can access the boundaries with mesh.boundaries() and try to snap the vertices to a closest common vertex. This script is not a solution, but I hope can give some ideas on how to proceed.
from vedo import *
# Paramters
a = 5
length = 100
width = 100
height = 10
def gen_strut(start, stop):
strut_param = np.ones((length, 1))
strut_param = strut_param * np.linspace(start, stop, width)
t = np.repeat(strut_param[:, :, np.newaxis], height, axis=2)
return t
scale=0.5
pi = np.pi
x, y, z = np.mgrid[:length, :width, :height]
cox = cos(scale * pi * x / a)
siy = sin(scale * pi * y / a)
coy = cos(scale * pi * y / a)
siz = sin(scale * pi * z / a)
coz = cos(scale * pi * z / a)
six = sin(scale * pi * x / a)
U1 = ((six ** 2) * (coy ** 2) +
(siy ** 2) * (coz ** 2) +
(siz ** 2) * (cox ** 2) +
(2 * six * coy * siy * coz) +
(2 * six * coy * siz * cox) +
(2 * cox * siy * siz * coz)) - (gen_strut(0, 1.3) ** 2)
iso = Volume(U1).isosurface(0).c('silver').backcolor("p5").lw(1).flat()
cube = TessellatedBox(n=(length-1, width-1, height-1)).c('red5').alpha(1)
cube.triangulate().compute_normals()
cube.cut_with_mesh(iso).compute_normals()
print(iso.boundaries(return_point_ids=True))
print(cube.boundaries(return_point_ids=True))
print(iso.boundaries().join().lines())
show(iso, cube).close()
merge(iso, cube).clean().backcolor("p5").show().close()
iso.clone().fill_holes(15).backcolor("p5").show().close()

Visualization of isolines in Matplotib on specific shape of mesh

I need some help with visualization in Matplotlib. I'm doing some Computational Fluid Dynamics and I have this kinda mesh, in which you can see the circular shape of floor. I've run some computations and from the data I gathered, I got this image of isolines
of Mach number. As you can see, the curved floor isn't present. How can I plot the isolines in the specified curved shape of the mesh?
This is my code:
mach = np.ndarray((nx, ny))
x = np.empty([nx])
y = np.empty([ny])
for index, cell in np.ndenumerate(mach):
p = (kappa - 1) * (w[index][3] - 0.5 *
(w[index][1] * w[index][1] + w[index][2] * w[index][2])
/ w[index][0])
v = np.sqrt((w[index][1] / w[index][0]) * (w[index][1] / w[index][0]) + (w[index][2] / w[index][0]) * (
w[index][2] / w[index][0]))
a = np.sqrt(kappa * p / w[index][0])
mach[index] = v / a
x[index[0]] = Mesh[index][0]
y[index[1]] = Mesh[index][1]
plt.figure(1)
X, Y = np.meshgrid(x, y, indexing='ij')
matplotlib.pyplot.contour(X, Y, mach, 50, cmap='turbo')
plt.show()
Thank you for your answers!

Meshgrid/lattice/matrix of an ellipse area

I'm likely using the wrong terms but seeking some help.
I would like to generate an array of x,y values for a grid that sits within the perimeter of an ellipse shape.
There is code here: http://people.sc.fsu.edu/~jburkardt/c_src/ellipse_grid/ellipse_grid.html to accomplish this in Python.
However, for my purpose the ellipses have been rotated to a certain degree. The current equation does not account for this and need some help to account for this transformation, unsure how to change the code to do this?
I've been looking into np.meshrid function as well, so if there are better ways to do this, please say.
Many thanks.
Given an ellipse in the Euclidean plane in its most general form as quadratic curve in the form
f(x,y) = a x^2 + 2b x y + c y^2 + 2d x + 2f y + g,
one can compute the center (x0,y0) by
((cd-bf)/(b^2-ac), (af-bd)/(b^2-ac))
(see equations 19 and 20 at Ellipse on MathWorld). The length of the major axis a_m can be computed by equation 21 on the same page.
Now it suffices to find all grid points (x,y) inside the circle with center (x0,y0) and radius a_m with
sign(f(x,y)) = sign(f(x0,y0)).
To generate lattice points inside ellipse, we have to know where horizontal line intersects that ellipse.
Equation of zero-centered ellipse, rotated by angle Theta:
x = a * Cos(t) * Cos(theta) - b * Sin(t) * Sin(theta)
y = a * Cos(t) * Sin(theta) + b * Sin(t) * Cos(theta)
To simplify calculations, we can introduce pseudoangle Fi and magnitude M (constants for given ellipse)
Fi = atan2(a * Sin(theta), b * Cos(theta))
M = Sqrt((a * Sin(theta))^2 + (b * Cos(theta))^2)
so
y = M * Sin(Fi) * Cos(t) + M * Cos(Fi) * Sin(t)
y/M = Sin(Fi) * Cos(t) + Cos(Fi) * Sin(t)
y/M = Sin(Fi + t)
and solution for given horizontal line at position y are
Fi + t = ArcSin( y / M)
Fi + t = Pi - ArcSin( y / M)
t1 = ArcSin( y / M) - Fi //note two values
t2 = Pi - ArcSin( y / M) - Fi
Substitute both values of t in the first equation and get values of X for given Y, and generate one lattice point sequence
To get top and bottom coordinates, differentiate y
y' = M * Cos(Fi + t) = 0
th = Pi/2 - Fi
tl = -Pi/2 - Fi
find corresponding y's and use them as starting and ending Y-coordinates for lines.
import math
def ellipselattice(cx, cy, a, b, theta):
res = []
at = a * math.sin(theta)
bt = b * math.cos(theta)
Fi = math.atan2(at, bt)
M = math.hypot(at, bt)
ta = math.pi/2 - Fi
tb = -math.pi/2 - Fi
y0 = at * math.cos(ta) + bt *math.sin(ta)
y1 = at * math.cos(tb) + bt *math.sin(tb)
y0, y1 = math.ceil(cy + min(y0, y1)), math.floor(cy + max(y0, y1))
for y in range(y0, y1+1):
t1 = math.asin(y / M) - Fi
t2 = math.pi - math.asin(y / M) - Fi
x1 = a * math.cos(t1) * math.cos(theta) - b* math.sin(t1) * math.sin(theta)
x2 = a * math.cos(t2) * math.cos(theta) - b* math.sin(t2) * math.sin(theta)
x1, x2 = math.ceil(cx + min(x1, x2)), math.floor(cx + max(x1, x2))
line = [(x, y) for x in range(x1, x2 + 1)]
res.append(line)
return res
print(ellipselattice(0, 0, 4, 3, math.pi / 4))

matplotlib reproducible plot

I am trying to plot a complex function with variable arguments in python and am finding a discrepancy I am unable to explain. My code is shown below:
import matplotlib.pyplot as plt
from numpy import pi, exp, real, imag, linspace
a = 1
b = 6
c = -14
coeff1 = 1
coeff2 = -1 / 2
coeff3 = 1j / 3
def f(t):
return (
coeff1 * exp(a * 1j * t) + coeff2 * exp(b * 1j * t) + coeff3 * exp(c * 1j * t)
)
t = linspace(0, 2 * pi, 1000)
ft = f(t)
plt.plot(real(ft), imag(ft))
plt.plot(
real(exp(1j * t) - exp(6j * t) / 2 + 1j * exp(-14j * t) / 3),
imag(exp(1j * t) - exp(6j * t) / 2 + 1j * exp(-14j * t) / 3),
)
# These two lines make the aspect ratio square
fig = plt.gcf()
fig.gca().set_aspect("equal")
plt.show()
I would expect that the two functions, shown in red and green in the plot, would be identical. But this is clearly not the case. Can someone please tell me what I am missing? Thanks.
Try to replace all integers with floats. Maybe it's an issue of python2 types.
On python3 I'm reproducing your code and they are equal. My dependencies versions are:
numpy==1.14.0
matplotlib==2.2.2
UPDATE. The problem is -1/2 which is equal -1 on python2

Plot a ball rolling down a curve

I want to "animate" a circle rolling over the sin graph, I made a code where the circle moves rapidly down a straight line, now I want the same but the acceleration will be changing.
My previous code:
import numpy as np
import matplotlib.pyplot as plt
theta = np.arange(0, np.pi * 2, (0.01 * np.pi))
x = np.arange(-50, 1, 1)
y = x - 7
plt.figure()
for t in np.arange(0, 4, 0.1):
plt.plot(x, y)
xc = ((-9.81 * t**2 * np.sin(np.pi / 2)) / 3) + (5 * np.cos(theta))
yc = ((-9.81 * t**2 * np.sin(np.pi / 2)) / 3) + (5 * np.sin(theta))
plt.plot(xc, yc, 'r')
xp = ((-9.81 * t**2 * np.sin(np.pi / 2)) / 3) + (5 * np.cos(np.pi * t))
yp = ((-9.81 * t**2 * np.sin(np.pi / 2)) / 3) + (5 * np.sin(np.pi * t))
plt.plot(xp, yp, 'bo')
plt.pause(0.01)
plt.cla()
plt.show()
You can do this by numerically integrating:
dt = 0.01
lst_x = []
lst_y = []
t = 0
while t < 10: #for instance
t += dt
a = get_acceleration(function, x)
x += v * dt + 0.5 * a * dt * dt
v += a * dt
y = get_position(fuction, x)
lst_x.append(x)
lst_y.append(y)
This is assuming the ball never leaves your slope! If it does, you'll also have to integrate in y in a similar way as done in x!!
Where your acceleration is going to be equal to g * cos(slope).

Categories