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.
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
Here is the problem. We have two points (spheres) in xyz, with this info:
1- x,y,z => The center of the object is currently located at
2- r => The collision radius of the object
3- Vx, Vy, Vz => object is traveling along the vector. If that vector is (0,0,0), the object is stationary.
Note: The radii and positions are in meters and velocities are measured in meters per second.
Question: For each test, output a single line containing the time (in seconds) since the start of the test at which the two objects will first collide. If they never collide, print No collision instead.
I want to know about the formula of calculation this time. Any idea would be appreciated.
Examples:
1-
xyz(1): -7 5 0
v(1): -1 0 3
r(1): 3
xyz(2): 10 7 -6
v(2): -2 0 4
r(2): 6
t: 8.628 // this is the answer
2-
xyz(1): 10 3 -10
v(1): -9 3 -8
r(1): 5
xyz(2): 2 0 0
v(2): 6
r(2): -4 3 -10
t: 0.492 // this is the answer
To simplify problem, let us use Halileo's principle. Consider the first object as base point, so the second objects moves relative to it.
Put the first object position in coordinate origin.
Subtract the first object initial coordinates from the second one coordinates, do the same for velocity components
x2_0 = x2_0 - x1_0 (same for y,z)
Vx2 = Vx2 - Vx1 (same for y,z)
Now we have second center coordinates against time
x = x2_0 + Vx2 * t
y = y2_0 + Vy2 * t
z = z2_0 + Vz2 * t
and squared distance to origin:
dd = x*x + y*y + z*z =
(x2_0 + Vx2 * t)^2 + ... =
x2_0^2 + 2*x2_0*Vx2*t + Vx2^2*t^2 + ...
and we need to calculate when dd becomes equal to squared radius sum (r1+r2)^2
t^2 * (Vx2^2+Vy2^2+Vz2^2) + t*(2*x2_0*Vx2+2*y2_0*Vy2+2*z2_0*Vz2) +
x2_0^2 + y2_0^2 + y2_0^2 - (r1+r2)^2 = 0
Solve this quadratic equation for t, get 0,1 or 2 solutions.
Case of 0 solutions - no collision
Case of 1 solution with positive t - moment of touching
Case of two solutions - get smaller positive t for the moment of collision.
Negative values of t mean collision "in the past", before the start of the test
Quick test in Python (ideone)
from math import sqrt, isclose
def collisiontime(x1,y1,z1,vx1,vy1,vz1,r1, x2,y2,z2,vx2,vy2,vz2,r2):
x2 -= x1
y2 -= y1
z2 -= z1
vx2 -= vx1
vy2 -= vy1
vz2 -= vz1
a = vx2**2 + vy2**2 + vz2**2
b = 2*x2*vx2 + 2*y2*vy2 + 2*z2*vz2
c = x2**2 + y2**2 + z2**2 - (r1+r2)**2
D = b**2-4*a*c
if D < 0:
return None
if isclose(D, 0):
return -b/2/a
return (-b - sqrt(D)) / 2 /a, (-b + sqrt(D)) / 2 /a
print(collisiontime(0, 0, 0, 2, 0, 0, 2, 25, 0, 0, -3, 0, 0, 3)) # 1=> <=2
print(collisiontime(0, 0, 0, 2, 0, 0, 2, 25, 5, 0, 1, 0, 0, 3)) # 1==> 2=> chase with touching
print(collisiontime(-7, 5, 0,-1, 0, 3, 3, 10, 7, -6, -2, 0, 4, 6))
print(collisiontime(10, 3, -10,-9, 3, -8,5, 2, 0, 0, -4, 3, -10, 6))
(4.0, 6.0)
25.0
(8.627718676730986, 14.372281323269014)
(0.4917797757201004, 3.646151258762658)
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'm trying to understand the rotation of the matrices using WebGL.
I got this mat4() matrix and I have to apply these transformations :
m = translate(torsoHeight+1*headHeight, 5, 0.0);
m = mult(m, rotate(theta[head1Id], 1, 0, 0))
m = mult(m, rotate(theta[head2Id], 0, 1, 0));
m = mult(m, translate(0.0, -0.5*headHeight, 0.0));
figure[headId] = createNode( m, head, leftUpperArmId, null);
break;
I did not understand exactly how the mult function works. The first parameter is my matrix.
The theta[] is built in this way :
var theta = [0, 0, 0, 0, 0, 0, 180, 0, 180, 0, 0];
and
var headId = 1;
var head1Id = 1;
var head2Id = 10;
Am I right if I thought that the second parameter is another matrix build with the rotate() function ? In this case how does the rotate function work ?
rotate and translate are functions that create matrices.
rotate looks like it's arguments are (angle, vectorx, vectory, vectorz) to create a matrix rotating points around the given vectory.
mult is the standard mathematical multiplication for 4x4 matrices.
You probably should dig in linear algebra tutorials such as https://open.gl/transformations
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.