Reputation: 1681
I want to draw curves between any two points in 3d space. The curve must be, umm, "vertical". I mean, x,y positions of the points of curve must be on the same line, but z values must change as if you sent a projectile from ground, it traveled in air, and hit the ground again. It does not need to be physically correct, an arc is OK.
This is the starting code:
import numpy as np
p1=np.array([1,1,1]) #x,y,z coordinates of the first point
p2=np.array([3,3,3]) #x,y,z coordinates of the second point
xi=np.linspace(p1[0],p2[0],100) #determine 100 x coordinates between two points
yi=np.linspace(p1[1],p2[1],100) #determine 100 y coordinates between two points
zi= ?? #determine 100 z coordinates between two points.
How can I determine those 100 z coordinates (zi
)?
After determining zi
it is trivial to draw lines between consecutive points(using mayavi or mplot3d) , giving the visual of a curve.
Upvotes: 4
Views: 3524
Reputation: 1681
I ended up using scipy.interpolate
to get the curve, and adding it to z coordinates of the line between points. As others said, there are more than one way to do this. This will be enough for my purpose.
### objective: draw an arc between points p1 and p2. z coordinates are raised.
import numpy as np
from scipy import interpolate
from mayavi import mlab
###inputs
p1=np.random.uniform(0,20,(3)) #first point
p2=np.random.uniform(0,20,(3)) #second point
npts = 100 # number of points to sample
y=np.array([0,.5,.75,.75,.5,0]) #describe your shape in 1d like this
amp=5 #curve height factor. bigger means heigher
#get the adder. This will be used to raise the z coords
x=np.arange(y.size)
xnew = np.linspace(x[0],x[-1] , npts) #sample the x coord
tck = interpolate.splrep(x,y,s=0)
adder = interpolate.splev(xnew,tck,der=0)*amp
adder[0]=adder[-1]=0
adder=adder.reshape((-1,1))
#get a line between points
shape3=np.vstack([np.linspace(p1[dim],p2[dim],npts) for dim in xrange(3)]).T
#raise the z coordinate
shape3[:,-1]=shape3[:,-1]+adder[:,-1]
#plot
x,y,z=(shape3[:,dim] for dim in xrange(3))
mlab.points3d(x,y,z,color=(0,0,0))
mlab.plot3d(x,y,z,tube_radius=1)
mlab.outline()
mlab.axes()
mlab.show()
Upvotes: 3
Reputation: 3571
There isn't one right answer to this question because the curvature of the arc isn't constrained. The basis for the math for this problem is projectile motion, which gives you two key equations:
x_2 - x_1 = v_1 cos theta dt
z_2 - z_1 = -1/2 g dt^2 + v_0 sin theta dt
where v_1 is the initial velocity of the projectile, theta is the angle from horizontal that the projectile is shot at, dt is the time it takes for the projectile to go from point 1 to point 2, and g is the gravitational constant. This neglects y for now for simplicity. The problem for you is that this gives you two equations, but you have three unknowns, v_1, theta, and dt.
You can add a constraint, for example, that the higher of p1 and p2 is the peak of the trajectory. If p2 is higher, for example,
v_2 = v_1 - g dt = 0
Solving those three equations gives you v_1, which gives the z coordinate over time:
z = -1/2 g t^2 + v_1 t + z_1
t = np.linspace(0, dt, 100)
gives you a numpy vector of times, and you can plug that into your formula for z.
Upvotes: 0