Is this the correct way to co-compute translation and rotation, or is there a better way? At the moment my code translates and then rotates, could that pose a problem?
Code
from math import cos, sin, radians
def trig(angle):
r = radians(angle)
return cos(r), sin(r)
def matrix(rotation=(0,0,0), translation=(0,0,0)):
xC, xS = trig(rotation[0])
yC, yS = trig(rotation[1])
zC, zS = trig(rotation[2])
dX = translation[0]
dY = translation[1]
dZ = translation[2]
return [[yC*xC, -zC*xS+zS*yS*xC, zS*xS+zC*yS*xC, dX],
[yC*xS, zC*xC+zS*yS*xS, -zS*xC+zC*yS*xS, dY],
[-yS, zS*yC, zC*yC, dZ],
[0, 0, 0, 1]]
def transform(point=(0,0,0), vector=(0,0,0)):
p = [0,0,0]
for r in range(3):
p[r] += vector[r][3]
for c in range(3):
p[r] += point[c] * vector[r][c]
return p
if __name__ == '__main__':
point = (7, 12, 8)
rotation = (0, -45, 0)
translation = (0, 0, 5)
matrix = matrix(rotation, translation)
print (transform(point, matrix))
Output
root#ubuntu:~$ python rotate.py
[-0.707106781186547, 12.0, 15.606601717798213]
well your matrix function is fine I got it working but for output I used this:
#def transform(point, vector):
# p = [0,0,0]
# for r in range(0,3):
# p[r] += vector[r][3]
# print p
# for c in range(3):
# p[r] += point[c] * vector[r][c]
# return p
def transform(point, TransformArray):
p = np.array([0,0,0,1])
for i in range (0,len(point)-1):
p[i] = point[i]
p=np.dot(TransformArray,np.transpose(p))
for i in range (0,len(point)-1):
point[i]=p[i]
return point
the theory behind it if instead of performing manual changes let the matrices sort it out. Here is where you can find the literature to better understand what I did: http://www.inf.ed.ac.uk/teaching/courses/cg/lectures/cg3_2013.pdf
And yes the way you perform your matrix function defines the way you perform the order of your transformations. There are 3 major transformations: Scaling, Translation, and Rotation. More on that in the link I sent.
Though matrix function works it seems you have the x and z rotations swapped by mistake now I could now follow any of your matrix indices so I rewrote it as such:
def matrix(rotation, translation):
xC, xS = trig(rotation[0])
yC, yS = trig(rotation[1])
zC, zS = trig(rotation[2])
dX = translation[0]
dY = translation[1]
dZ = translation[2]
Translate_matrix = np.array([[1, 0, 0, dX],
[0, 1, 0, dY],
[0, 0, 1, dZ],
[0, 0, 0, 1]])
Rotate_X_matrix = np.array([[1, 0, 0, 0],
[0, xC, -xS, 0],
[0, xS, xC, 0],
[0, 0, 0, 1]])
Rotate_Y_matrix = np.array([[yC, 0, yS, 0],
[0, 1, 0, 0],
[-yS, 0, yC, 0],
[0, 0, 0, 1]])
Rotate_Z_matrix = np.array([[zC, -zS, 0, 0],
[zS, zC, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]])
return np.dot(Rotate_Z_matrix,np.dot(Rotate_Y_matrix,np.dot(Rotate_X_matrix,Translate_matrix)))
As you can see the sequence of transforms in my return will change the output: since the last is the translation it will translate the point first then rotate in X , then rotate in Y and finally in Z.
Hope this helps cheers bud.
As this is a highly viewed post I thought it would be useful to lead people to the SciPy Rotation Class which I found very useful for rotations, and would have been a good solution for the question, had it been around at the time.
Related
From the 3 black points I found the plane
const { Vector3, Plane } = require('three')
const points = [new Vector3(0, 0, 0), new Vector3(1, 0, 1), new Vector3(1, 2, 0)]
const plane = new Plane().setFromCoplanarPoints(...points)
But how do I get the Z coordinate of the fourth red point (example: (0.75, 0.75, z)) that lies in the plane?
This doesn't seem to work:
const targetPoint = new Vector3()
plane.projectPoint(new Vector3(0.75, 0.75, 0), targetPoint)
/*
Vector3 {
x: 0.5833333333333334,
y: 0.8333333333333334,
z: 0.16666666666666666
}
*/
An answer with TurfJS would be also perfectly OK
Just for others to know, I solved with TurfJS using its method planepoint.
The method polygon has as 1st parameter an array of Linear Rings, and a Linear Ring must have the same first and last points, thus a triangle has 4 points. a, b, c represent the ordered heights.
const turf = require('#turf/turf')
const point = turf.point([0.75, 0.75])
const triangle = turf.polygon([[
[0, 0], [1, 0], [1, 2], [0, 0]
]], {
a: 0,
b: 1,
c: 0
})
const zValue = turf.planepoint(point, triangle) // 0.375
I want to construct a rotation matrix, which have unknown Eular angles. I want to build some regression solution to find the value of Eular angles. My code is here.
roll = yaw = pitch = torch.randn(1,requires_grad=True)
RX = torch.tensor([
[1, 0, 0],
[0, cos(roll), -sin(roll)],
[0, sin(roll), cos(roll)]
],requires_grad=True)
RY = torch.tensor([
[cos(pitch), 0, sin(pitch)],
[0, 1, 0],
[-sin(pitch), 0, cos(pitch)]
],requires_grad=True)
RZ = torch.tensor([
[cos(yaw), -sin(yaw), 0],
[sin(yaw), cos(yaw), 0],
[0, 0, 1]
],requires_grad=True)
R = torch.mm(RZ, RY).requires_grad_()
R = torch.mm(R, RX).requires_grad_()
R = R.mean().requires_grad_()
R.backward()
Matrix cannot differentiate the Euler angles.
There isn't any gradient value of matrix. Can anyone fix my problems? Thanks!
debug result
torch.tensor is viewed as an operation and that is not able to do backpropgation.
A dirty way to fix your code:
roll = torch.randn(1,requires_grad=True)
yaw = torch.randn(1,requires_grad=True)
pitch = torch.randn(1,requires_grad=True)
tensor_0 = torch.zeros(1)
tensor_1 = torch.ones(1)
RX = torch.stack([
torch.stack([tensor_1, tensor_0, tensor_0]),
torch.stack([tensor_0, cos(roll), -sin(roll)]),
torch.stack([tensor_0, sin(roll), cos(roll)])]).reshape(3,3)
RY = torch.stack([
torch.stack([cos(pitch), tensor_0, sin(pitch)]),
torch.stack([tensor_0, tensor_1, tensor_0]),
torch.stack([-sin(pitch), tensor_0, cos(pitch)])]).reshape(3,3)
RZ = torch.stack([
torch.stack([cos(yaw), -sin(yaw), tensor_0]),
torch.stack([sin(yaw), cos(yaw), tensor_0]),
torch.stack([tensor_0, tensor_0, tensor_1])]).reshape(3,3)
R = torch.mm(RZ, RY)
R = torch.mm(R, RX)
R_mean = R.mean()
R_mean.backward()
I have a 3x3 Convolution Function defined like this
conv(x, y) = 0;
conv(x, y) += kernel(r.x, r.y) * in(x + r.x - 1, y + r.y - 1);
Size of the input buffer is 16 x 16
If I want to execute it with padding I can directly do
in = Halide::BoundaryConditions::constant_exterior(in_buffer, 0, 0, 16, 0, 16)
But I have to execute without padding and so I am trying to manually set the bounds on the function like this
conv.bound(x, 1, 14);
conv.bound(y, 1, 14);
This returns an error message
Error:
Bounds given for convolution in y (from 1 to 14) do not cover required region (from 0 to 15)
What should I do to set bounds on a Var in Func?
I think you need not to manually set the bounds using the *.bound function. Try this one:
Halide::Func conv("conv"), kernelF("kernel"), in("in");
Halide::Var x("x"), y("y");
Halide::RDom r(0, 3, 0, 3,"r");
in = Halide::BoundaryConditions::constant_exterior(in_buffer, 0,
0, 16, 0, 16);
kernelF = Halide::BoundaryConditions::constant_exterior(kernel_buffer, 0,
0, 3, 0, 3);
conv(x, y) = 0.0f;
conv(x, y) += kernelF(r.x, r.y) * in(x + r.x, y + r.y);
//conv.print_loop_nest();
Halide::Buffer<float_t> outputBuf = conv.realize(14, 14);
Look, we can set the bounds directly in *.realize() arguments, i.e. 14=16-3+1; Also, note that the convolution anchors are at the top-left of kernels.
I want to write a ruby program that steps over space in an arbitrary number of dimensions.
In 3 dimensions what I'm doing looks like this:
x_range = (-1..1)
y_range = (-1..1)
z_range = (-1..1)
step_size = 0.01
x_range.step(step_size) do |x|
y_range.step(step_size) do |y|
z_range.step(step_size) do |z|
# do something with the point x,y,z
end
end
end
I want to do the same for n dimensions
This is the first thing that comes to mind for me:
def enumerate(nDimens, bottom, top, step_size)
bottom = (bottom / step_size).to_i
top = (top / step_size).to_i
range = (bottom..top).to_a.map{ |x| x * step_size }
return range.repeated_permutation(nDimens)
end
stepper = enumerate(4, -1, 1, 0.1)
loop do
puts "#{stepper.next()}"
end
This produces:
[-1.0, -1.0, -1.0, -1.0]
[-1.0, -1.0, -1.0, -0.9]
[-1.0, -1.0, -1.0, -0.8]
# Lots more...
[1.0, 1.0, 1.0, 0.8]
[1.0, 1.0, 1.0, 0.9]
[1.0, 1.0, 1.0, 1.0]
This assumes all dimensions have the same range, but it'd be easy to adjust if for some reason that doesn't hold.
Recursion could solve this kind of problem easily and perfectly. Code below fits any number of dimensions, and also various length of ranges.
def traversal(ranges, step_size, conjunction = [], &blk)
ranges[0].step(step_size) do |x|
conjunction.push(x)
if ranges.size > 1
traversal(ranges[1..-1], step_size, conjunction, &blk)
else
blk.call(conjunction) if block_given?
conjunction.pop
end
end
conjunction.pop
end
Run: (dimension = 4, length = 3, 3, 4, 2)
x = (1..3)
y = (4..6)
z = (7..10)
w = (100..101)
test_data = [x, y, z, w]
step_size = 1
traversal(test_data, step_size) do |x|
puts "Point: #{x.join('-')}"
end
Output: (72 points in total, which is 3 * 3 * 4 * 2)
Point: 1-4-7-100
Point: 1-4-7-101
Point: 1-4-8-100
Point: 1-4-8-101
Point: 1-4-9-100
Point: 1-4-9-101
Point: 1-4-10-100
Point: 1-4-10-101
Point: 1-5-7-100
Point: 1-5-7-101
Point: 1-5-8-100
Point: 1-5-8-101
Point: 1-5-9-100
Point: 1-5-9-101
Point: 1-5-10-100
Point: 1-5-10-101
Point: 1-6-7-100
Point: 1-6-7-101
Point: 1-6-8-100
Point: 1-6-8-101
Point: 1-6-9-100
Point: 1-6-9-101
Point: 1-6-10-100
Point: 1-6-10-101
Point: 2-4-7-100
Point: 2-4-7-101
Point: 2-4-8-100
Point: 2-4-8-101
Point: 2-4-9-100
Point: 2-4-9-101
Point: 2-4-10-100
Point: 2-4-10-101
Point: 2-5-7-100
Point: 2-5-7-101
Point: 2-5-8-100
Point: 2-5-8-101
Point: 2-5-9-100
Point: 2-5-9-101
Point: 2-5-10-100
Point: 2-5-10-101
Point: 2-6-7-100
Point: 2-6-7-101
Point: 2-6-8-100
Point: 2-6-8-101
Point: 2-6-9-100
Point: 2-6-9-101
Point: 2-6-10-100
Point: 2-6-10-101
Point: 3-4-7-100
Point: 3-4-7-101
Point: 3-4-8-100
Point: 3-4-8-101
Point: 3-4-9-100
Point: 3-4-9-101
Point: 3-4-10-100
Point: 3-4-10-101
Point: 3-5-7-100
Point: 3-5-7-101
Point: 3-5-8-100
Point: 3-5-8-101
Point: 3-5-9-100
Point: 3-5-9-101
Point: 3-5-10-100
Point: 3-5-10-101
Point: 3-6-7-100
Point: 3-6-7-101
Point: 3-6-8-100
Point: 3-6-8-101
Point: 3-6-9-100
Point: 3-6-9-101
Point: 3-6-10-100
Point: 3-6-10-101
If ranges are not too big you can do something like this:
n = 5 # 5 dimentions
x = (-1..1).to_a
x.product(*[x]*(n-1)).each {|i| p i}
Result:
[-1, -1, -1, -1, -1]
[-1, -1, -1, -1, 0]
[-1, -1, -1, -1, 1]
[-1, -1, -1, 0, -1]
[-1, -1, -1, 0, 0]
[-1, -1, -1, 0, 1]
[-1, -1, -1, 1, -1]
[-1, -1, -1, 1, 0]
[-1, -1, -1, 1, 1]
[-1, -1, 0, -1, -1]
[-1, -1, 0, -1, 0]
# skipped
This is what you could do... here is an example iterator.
#next(l[dim] array of lower ranges ,h[dim] = upper ranges, step[dim], dim = dimensions -1, curr[dim] = current state in dim dimensions )
def nextx(l ,h, step, dim, curr)
x = dim
update= false
while (update==false)
if curr[x] == h[x]
if x > 0
x = x-1
else
exit
end
else
curr[x]= curr[x]+step[x]
while (x < dim)
x = x+1
curr[x] = l[x]
end
update = true
end
end
return curr
end
l = [0,0,0]
h = [3,3,3]
step = [1,1,1]
currx = [0,0,2]
i = 0
while i < 70
currx = nextx(l, h, step, 2, currx)
puts currx.inspect
i=i+1
end
This is typically encountered in algorithms that explore a search space. The do loops are creating a product space from the one dimensional ranges.
First pack as many ranges are needed into an array e.g.
search_space_1Ds = [x_range.step(step_size).to_a, y_range.step(step_size).to_a, z_range.step(step_size).to_a]
then the following will work with an arbitrary number of dimensions.
search_space = search_spaces_1Ds.shift.product(*search_space_1Ds)
search_space.map do |vec|
# calculate something with vec
end
This implementation is not only concise, it makes it very clear what your algorithm is doing; enumerating through a search space that is created as the product space of the one dimensional search spaces.
It's apparently very simple but I can't find my mistake. The Plot gives me no points at all.
tmax = 1.;
nmax = 10;
deltat = tmax/nmax;
h[t_, s_] := t^2 + s^2;
T = Table[{{n*deltat}, {n*deltat}, h[n*deltat, n*deltat]}, {n, 0, nmax}]
inth = ListInterpolation[T]
Plot3D[inth[s, t], {s, 0, 1}, {t, 0, 1}]
Any help would be mostly welcome!
Marco
I think your "T" is supposed to be a list of 3D points, in which case you should generate it with:
tmax = 1.;
nmax = 10;
deltat = tmax/nmax;
h[t_, s_] := t^2 + s^2;
T = Table[{n*deltat, n*deltat, h[n*deltat, n*deltat]}, {n, 0, nmax}]
inth = ListInterpolation[T]
Plot3D[inth[s, t], {s, 0, 1}, {t, 0, 1}]
Now T[[1]] = {0., 0., 0.} and not {{0.}, {0.}, 0.} as before.