Help the math challenged jamesk


(Jamesk) #1

I’ve got this problem. A bit embarrasing, but here goes: I don’t know any linear algebra! [snicker, what a bonehead]…

I need your help on this.

a) Assume that DV is a directional vector
b) Assume that P1 is a point in space

Now I need to calculate where P1 would end up if I move it, say 1 unit in the direction indicated by DV.

So, I would need a function like


def moveIt(point_of_origin, distance_to_move, direction):
     #fill in this blank
     return the_new_point

Could someone fill this func with the necessary stuff for me?
Thanks in advance.


(Jamesk) #2

Well, this far along I know that there are at least 10 others that don’t know how to do this either. I’m obviously not alone :smiley: :smiley: :smiley:


(d0pamine) #3

This would be my approach, assuming the arguments are lists in python:


def moveIt(point_of_origin, distance_to_move, direction):
     # make sure 'direction' is normalized (length == 1)
     point_of_origin[0] += distance_to_move * direction[0]
     point_of_origin[1] += distance_to_move * direction[1]
     point_of_origin[2] += distance_to_move * direction[2]
     return point_of_origin

You can see that if direction = [0,0,1], the point would move in the z direction exactly distance_to_move units.

Cheers,
Tom


(theeth) #4

using this module called vecf.py


"""
	VECTOR FUNCTIONS
"""
from math import *
from dynoise import random, randuvec

# Return a new vector initialised to zero
def ZeroVector():
	return [0.0, 0.0, 0.0]

#resize a until it is the same lenght as b, while retaining the orientation
def resize(a,b):
	return vecmul( vnorm(a), veclen(b) )

def vecadd(a,b):
	return [a[0]+b[0], a[1]+b[1], a[2]+b[2]]

def vecsub(a,b):
	return [a[0]-b[0], a[1]-b[1], a[2]-b[2]]

def vecmul(a, s):
	return [a[0]*s, a[1]*s, a[2]*s]

def vecdiv(a, s):
	if s!=0.0: s = 1.0/s
	return vecmul(a, s)

# transform a Cartesian vector into a Geographic oriented vector ANGLES ARE IN DEGREES
def makeGeo(v):
	tv = [0.0, 0.0, 0.0]
	tv[0] = veclen(v)
	tv[1] = atan2(v[0], v[1]) * 180 / pi
	tv[2] = asin(vecnorm(v)[2]) * 180 / pi
	return tv

# transfrom a geographic vector into a Cartesian vector ANGLES ARE IN DEGREES
def makeCart(v):
	v[1] = v[1] / 180 * pi
	v[2] = v[2] / 180 * pi
	tv = [0.0, 0.0, 0.0]
	tv[0] = v[0] * cos(v[2]) * cos(v[1])
	tv[1] = v[0] * cos(v[2]) * sin(v[1])
	tv[2] = v[0] * sin(v[2])
	return tv

# return a copy of a vector, this is to prevent cross referencing
# like vector1 = vector2 which both point to the same object
def vcopy(v):
	return [v[0], v[1], v[2]]

# normalize, but don't modify
def vecnorm(v):
	# normalize vector
	d = vdot(v, v)
	if d>0.0: d = 1./sqrt(d)
	return vecmul(v, d)

# normalize
def vnorm(v):
	# normalize vector
	d = vdot(v, v)
	if d>0.0:
		d = 1./sqrt(d); v[0]*=d; v[1]*=d; v[2]*=d
	return v

# normalize and return length
def vnormlen(v):
	# normalize vector
	d = vdot(v, v)
	if d>0.0:
		d = sqrt(d)
		dv = 1./d; v[0]*=dv; v[1]*=dv; v[2]*=dv
	return d

# normalize and return length squared
def vnormlensq(v):
	# normalize vector
	d = vdot(v, v)
	if d>0.0:
		dv = 1./sqrt(d); v[0]*=dv; v[1]*=dv; v[2]*=dv
	return d

# dotproduct
def vdot(v1, v2):
	# dot product
	return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]

# vector length
def veclen(v):
	return sqrt(vdot(v, v))

# crossproduct
def crossp(v1, v2):
	r = ZeroVector()
	r[0] = v1[1]*v2[2] - v1[2]*v2[1]
	r[1] = v1[2]*v2[0] - v1[0]*v2[2]
	r[2] = v1[0]*v2[1] - v1[1]*v2[0]
	return r

# scaled random vector
def randvecs(s):
	v = randuvec()
	v[0]*=s; v[1]*=s; v[2]*=s
	return v

##################################
# random emitter shape functions #
##################################

# These are now all in the same format, so the function can be a stored as a 'pointer'
# All return two values, position and velocity

def RandomLine(vs):
	return [vs[0] * (2.0 * random()-1.0), 0.0, 0.0], randuvec()

def RandomPlane(vs):
	return [vs[0] * (2.0 * random()-1.0), vs[1] * (2.0 * random() - 1.0), 0.0], randuvec()

def RandomDisc(vs):
	v = randuvec()
	return [vs[0] * v[0], vs[1] * v[1], 0.0], randuvec()

def RandomCylinder(vs):
	v = randuvec()
	return [vs[0] * v[0], vs[1] * v[1], vs[2] * (2.0*random()-1.0)], randuvec()

def RandomCone(vs):
	v = randuvec()
	return [vs[0] * v[0], vs[1] * v[1], vs[2] * sqrt(v[0]*v[0]+v[1]*v[1])], randuvec()

def RandomSphere(vs):
	v = randvecs(random())
	return [vs[0] * v[0], vs[1] * v[1], vs[2] * v[2]], randuvec()

def RandomCube(vs):
	v = [2.0 * (random() - 0.5), 2.0 * (random() - 0.5), 2.0 * (random() - 0.5)]
	return [vs[0] * v[0], vs[1] * v[1], vs[2] * v[2]], randuvec()

# used for mesh and point emitters
def RandomConeVelocity(angle):
	ty = 6.283185307 * random()
	tp = 1.570796327 + angle * random()
	return [-sin(ty)*cos(tp), cos(tp)*cos(ty), sin(tp)]

# For reasons of consistency it is called RandomPoint, but it always returns [0,0,0]
# vs not used as scale, vs[2] is used to store angle
def RandomPoint(vs):
	return ZeroVector(), RandomConeVelocity(vs[2])

#######################

# calculate reflected direction
def reflect(dirc, norm):
	ndir = ZeroVector()	# new direction
	t = -2.0 * vdot(dirc, norm)
	ndir[0] = t * norm[0] + dirc[0]
	ndir[1] = t * norm[1] + dirc[1]
	ndir[2] = t * norm[2] + dirc[2]
	return ndir

#######################

# Curve calculation (cubic hermite interpolation)
# From p1 to p2, p0 & p3 are the points before and after these points to calculate the gradient
# t is the time value
def HCurve(p0, p1, p2, p3, t):
	t2 = t * t
	t3 = t2 * t
	kp0 = (2.0 * t2 - t3 - t) * 0.5
	kp1 = 1.5 * t3 - 2.5 * t2 + 1.0
	kp2 = (4.0 * t2 - 3.0 * t3 + t) * 0.5
	kp3 = (t3 - t2) * 0.5
	r = ZeroVector()
	r[0] = p0[0] * kp0 + p1[0] * kp1 + p2[0] * kp2 + p3[0] * kp3
	r[1] = p0[1] * kp0 + p1[1] * kp1 + p2[1] * kp2 + p3[1] * kp3
	r[2] = p0[2] * kp0 + p1[2] * kp1 + p2[2] * kp2 + p3[2] * kp3
	return r

# alternate method, cubic interpolation, same arguments as HCurve
def CCurve(p0, p1, p2, p3, t):
	t2 = t * t
	t3 = t2 * t
	d01 = vecsub(p0, p1)
	a = vecsub(vecsub(p3, p2), d01)
	b = vecsub(d01, a)
	c = vecsub(p2, p0)
	r = ZeroVector()
	r[0] = a[0]*t3 + b[0]*t2 + c[0]*t + p1[0]
	r[1] = a[1]*t3 + b[1]*t2 + c[1]*t + p1[1]
	r[2] = a[2]*t3 + b[2]*t2 + c[2]*t + p1[2]
	return r

#########################
# MATRIX FUNCTIONS
#########################

#returns a list of list of float from a Matrix object (unpickleable)
def convertFL(mtx):
	fmtx = []
	for row in mtx:
		fmtx.append([x for x in row])
	return fmtx

# returns 3x3 identity matrix
def MtxIdentity3x3():
	return [[ 1.0, 0.0, 0.0],
			[ 0.0, 1.0, 0.0],
			[ 0.0, 0.0, 1.0]]

# returns 4x4 identity matrix
def MtxIdentity4x4():
	return [[ 1.0, 0.0, 0.0, 0.0],
			[ 0.0, 1.0, 0.0, 0.0],
			[ 0.0, 0.0, 1.0, 0.0],
			[ 0.0, 0.0, 0.0, 1.0]]

# multiplies two matrices, d determines 3x3(d=3) or 4x4(d=4)
def mulmat(m1, m2, d):
	r = MtxIdentity4x4()	#just for initialisation
	for i in range(d):
		for j in range(d):
			rij = 0.0
			for k in range(d): rij += m1[i][k] * m2[k][j]
			r[i][j] = rij
	return r

# multiply 3X3 matrix (rotation, scaling) with vector
def mulmatvec3x3(m, v):
	r = ZeroVector()
	r[0] = v[0]*m[0][0] + v[1]*m[1][0] + v[2]*m[2][0]
	r[1] = v[0]*m[0][1] + v[1]*m[1][1] + v[2]*m[2][1]
	r[2] = v[0]*m[0][2] + v[1]*m[1][2] + v[2]*m[2][2]
	return r

# multiply 4X3 matrix (rotation, scaling & translation) with vector
def mulmatvec4x3(m, v):
	r = ZeroVector()
	r[0] = v[0]*m[0][0] + v[1]*m[1][0] + v[2]*m[2][0] + m[3][0]
	r[1] = v[0]*m[0][1] + v[1]*m[1][1] + v[2]*m[2][1] + m[3][1]
	r[2] = v[0]*m[0][2] + v[1]*m[1][2] + v[2]*m[2][2] + m[3][2]
	return r

# transpose 3X3 matrix, the inverse rotation matrix
def transp3x3(m):
	r = MtxIdentity3x3()
	for i in range(3):
		for j in range(3): r[i][j] = m[j][i]
	return r

# creates rotation matrix around X, Y or Z
# axis must be 'X', 'Y' or anything else=='Z'
# angle in radians, all made equivalent to blenders matrices from RotXYZ
def makeRotMtx(axis, angle):
	if axis=='X':	
		rs, rc = sin(angle), cos(angle)
		mtx = [	[1.0, 0.0, 0.0],
				[0.0,  rc, rs],
				[0.0, -rs, rc] ]
	elif axis=='Y':
		rs, rc = sin(angle), cos(angle)
		mtx = [	[ rc, 0.0, -rs],
				[0.0, 1.0, 0.0],
				[ rs, 0.0,  rc] ]
	else:
		rs, rc = sin(angle), cos(angle)
		mtx = [	[ rc,  rs, 0.0],
				[-rs,  rc, 0.0],
				[0.0, 0.0, 1.0] ]
	return mtx

# creates full 3D rotation matrix
# rx, ry, rz angles in radians
def makeRotMtx3D(rx, ry, rz):
	# old slow indirect method
	#mtx_x = makeRotMtx('X', rx)
	#mtx_y = makeRotMtx('Y', ry)
	#mtx_z = makeRotMtx('Z', rz)
	#mtx = mulmat(mulmat(mtx_x, mtx_y, 3), mtx_z, 3)
	# faster equivalent
	# mtx_x =	[1, 0, 0]
	#			[0, B, A]
	#			[0,-A, B]
	# mtx_y =	[D, 0, -C]
	#			[0, 1,  0]
	#			[C, 0,  D]
	# 1.D +  0.0 +  0.C, 1.0 +  0.1 +  0.0, 1.-C +  0.0 +  0.D =  D,  0, -C
	# 0.D +  B.0 +  A.C, 0.0 +  B.1 +  A.0, 0.-C +  B.0 +  A.D = AC,  B, AD
	# 0.D + -A.0 +  B.C, 0.0 + -A.1 +  B.0, 0.-C + -A.0 +  B.D = BC, -A, BD
	# mtx_xy =	[ D, 0,  -C]
	#			[AC, B,  AD]
	#			[BC, -A, BD]
	# mtx_z =	[ F, E, 0]
	#			[-E, F, 0]
	#			[ 0, 0, 1]
	# D.F + 0.-E + -C.0 , D.E + 0.F + -C.0 , D.0 + 0.0 + -C.1 = DF, DE, -C
	# AC.F + B.-E + AD.0 , AC.E + B.F + AD.0 , AC.0 + B.0 + AD.1 = ACF-BE, ACE+BF, AD
	# BC.F + -A.-E + BD.0 , BC.E + -A.F + BD.0 , BC.0 + -A.0 + BD.1 = BCF+AE, BCE-AF, BD
	A, B = sin(rx), cos(rx)
	C, D = sin(ry), cos(ry)
	E, F = sin(rz), cos(rz)
	AC, BC = A*C, B*C
	return [[D*F, 	   D*E, 	 -C],
			[AC*F-B*E, AC*E+B*F, A*D],
			[BC*F+A*E, BC*E-A*F, B*D]]

# creates rotation matrix from a normalized direction vector
# z-rotation is ignored!
def makeRotMtx_fromVec(tv):
	v = vcopy(tv)
	v[1], v[2] = v[2], v[1]
	r = v[0]*v[0] + v[1]*v[1]
	if r>0.0: r = (acos(v[2]) / sqrt(r)) / pi
	u, v = v[0]*r, v[1]*r
	theta, phi = atan2(v, u), pi*sqrt(u*u + v*v)
	mtx = makeRotMtx3D(phi+0.5*pi, 0.5*pi-theta, 0.0)
	return mtx

you can do


DV = [x, y, z]
P1 = [x, y, z]
S = Scalar

Final = vecadd(vecmul(DV, S), P1)

I hope that’s more clear.

feel free to use the vecf module as you want.

Martin


(Jamesk) #5

Thanks, dewds… my math-challenge-o-meter just went down one notch. I’ll try those suggestions!