Slice a Matrix into a Vector

Hello there,

I started learning Rust and felt comfortable enough to build something. Being a Robotics Engineer naturally I wanted to build a kinematics/dynamics library. I know that there is already stuff out there, but this serves more as a learning-the-language for me. I want to implement something I am familiar with in a new language.

Now after a few hours I am quite frustrated. I have to say that I am coming from numpy where I can slice and stack matrices like a crazy person and feel quite comfortable. I knew I had to give this up but man I hit so many road blocks, I did not expect this.
Anyways here is my problem:

Disclaimer: I have seen that nalgebra seems to have Transformations already build in. But as I said I want to try to build a lil library myself also to understand how to deal with matrices.

So lets say I want to store a 4x4 transformation matrix with nalgebra.
So I have a struct that is holding a Matrix like this:

    pub struct TF {
        T: Matrix4<f32>,
    }

Now, this thing falls out of a forward kinematics function, and I want to retrieve quaternion and position from it. And I am already struggling with the most easy case (getting the position vector out).

So in my impl block I have a function that shall just return a 3 dimensional vector. In Numpy I would just

return self.T[0:3, 3]

However I know this is not Pyton and so I expected to somehow be able to get a Vector3<f32> out of my Matrix.

My first attempt was this. I also tried fixed_rows which did not work:

pub fn get_p(&self) -> Vector3<f32> {
    self.T.fixed_slice::<U3, U1>(0, 3) as Vector3<f32>
    }

Okay this does not work. With or without the explicit type cast, the types don’t match. And here I thought a Vector3 is just a VectorN is just a MatrixNM, …

Maybe there is a ::from method I could use on Vector? I am so confused about how to use this library. The Docs looked so fancy but I seem to be too stupid to understand it very well. So, why can I not do something like:

let my_cool_vector = Vector3::from_fixed_slice(my_cool_matrix, slice_stuff)

Anyway any help on how to do slices right, would be very much appreciated. I am using version 0.20.0.

As a bonus: In my frustration, I looked more into the docs and found a transformation struct. Cool! As I said, I wanna build this myself to understand, but maybe I could use this for now to make some progress. But I could not find a function that just returns the position vector. I mean any transformation matrix consists of two things really: a rotation matrix and a position vector. If I write an abstraction, I should be able to get either out of that abstraction somehow. I could not figure out how.

Anyways, sorry for long post. I will be lying down in a fetal position now and contemplate on life until someone responded. Please do not take my frustrations as criticism. As I said, I am new to the language and have mostly worked with C++ and Python recetly.

Lol. I think I figured it out!

I think it is just:

pub fn get_p(&self) -> Vector3<f32> {
    Vector3::from(self.T.fixed_slice::<U3, U1>(0, 3))
}

Okay all good, love your work. Stay healthy!

Hi!

Hopefully a few answers will help get you out of your frustration.

About the ‘as’ keyword

self.T.fixed_slice::<U3, U1>(0, 3) as Vector3<f32>

This is impossible in Rust. You can’t expect as to work for anything except a few predetermined case (casting between pointers like *const and *mut, casting between primitive types like u32, i64, and casting a struct to a trait-object). There is no way for anyone to overload the behavior of the as keyword for their own types.

About matrix slices

Rust is strongly typed and has nearly no automatic cast feature. Therefore, it is not possible to automatically cast a slice (which contain a pointer to another matrix) to an owned vector (which contains its own data buffer).

In nalgebra, it is true that a Vector3 is just a VectorN which is just a MatrixNM. But that only means that all vectors and matrices will work well together for mathematics operations. However, there are still a few differences between some types: a vector slice is not the same as a vector that owns its data buffer.

When you do let slice = self.T.fixed_slice::<U3, U1>(0, 3), you obtain a value slice which is a view over T. And this view only contains a pointer toward the data buffer of T. This is not the same as a Vector3 which owns its own data buffer. In order to convert a 3D vector slice/view into a 3D vector that owns its data buffer, you can call .into_owned() or .clone_owned() (the first one will move out of your variable, while the second one doesn’t):

pub fn get_p(&self) -> Vector3<f32> {
    self.T.fixed_slice::<U3, U1>(0, 3).into_owned()
}

Using Vector3::from(self.T.fixed_slice::<U3, U1>(0, 3)) or equivalently self.T.fixed_slice::<U3, U1>(0, 3).into() will work as well (it has been added more recently, so we still have into_owned for backward compatibility).

About transformation types

In my frustration, I looked more into the docs and found a transformation struct. Cool! […] But I could not find a function that just returns the position vector. I mean any transformation matrix consists of two things really: a rotation matrix and a position vector.

Are you referring to the Transform3 type? If so, then this is not the type you want to use. As the documentation says, this is a 3D general transformation that may not be invertible. Stored as a homogeneous 4x4 matrix. So in other words it can be the composition of anything, including non-linear scale, shear. It can even represent an homogeneous 3D projection matrix which does not even have a clearly defined “translation vector”. So it does not make sense to have a method that returns a translation vector if the underlying matrix may not even have one.

You may be interested to see the schematics on that section of the user guide. It shows each transformation type and their differences.

Don’t forget that nalgebra is a general-purpose library. So a word like Transform refers to something much broader than what is usually called a transformation in robotics. The type you are looking for are rigid-body transformations, aka. elements of SE(3), aka. direct isometries. In nalgebra, they are represented by the type Isometry3.

2 Likes

Thank you so much for taking the time to answer a total newbie like myself. I cannot stress enough how helpful this is for frustrated beginners like myself. Really really appreciate this!

Are you referring to the Transform3 type?

I was talking about nalgebra::geometry::Transform, it sounded like exactely what I needed: “A transformation matrix in homogeneous coordinates.”

But to be clear, I do not expect nalgebra to do this, in fact I think it would be annoying if one library tries to write use cases for all possible applications. I am totally fine with writing these things myself if I can build ontop of a solid linalg lib.

Again thank you!

One last thing:
I did not find the VectorN::from(...) or any generic ::from( on the Quick Ref or the Vectors and matrices page. I would’ve probably tried that out. Maybe its a good idea to put that there.

That’s a good idea, yeah. I’ve created an issue as a reminder to add this. We should also mention other implementation of From that exist in nalgebra.

1 Like