I'm playing with rasterization and ray tracing, and my algorithm works on objects that can be rotated, translated, scaled, and converted to a bunch of triangles. I implement this by creating the IntoTriangle trait:
pub trait IntoTriangle {
fn triangulate(&self) -> Vec<Triangle>;
fn rotate(&mut self, x: f32, y: f32, z: f32);
fn scale(&mut self, x: f32, y: f32, z: f32);
fn translate(&mut self, x: f32, y: f32, z: f32);
}
And then in my program I transform the object before converting it into triangles:
let obj = MyObjectType::new(...);
obj.scale(7.0, 7.0, 7.0);
obj.rotate(0.0, 45.0, 0.0);
obj.translate(3.0, 0.0, -30.0);
let triangles = obj.triangulate();
This code has been working for a long time. But recently I was going through a piece of unrelated code from gtk-rs and noticed how they stack up such calls in a very nice way, which I really loved because the usage becomes so much clearer:
let triangles = MyObjectType::new(...)
.scale(7.0, 7.0, 7.0)
.rotate(0.0, 45.0, 0.0)
.translate(3.0, 0.0, -30.0)
.triangulate();
To achieve this I would need to change scale/rotate/translate functions to take mut self and return Self (this is inspired by the gtk-rs code: https://gtk-rs.org/gtk4-rs/stable/latest/docs/src/gtk4/auto/application_window.rs.html#428-431 ):
fn rotate(mut self, x: f32, y: f32, z: f32) -> Self {
self.rotation = [x, y, z];
self
}
But this is not object-safe and the compiler won't let me do this unless I move these functions out of the trait. Is there any other way of achieving similar behaviour for trait objects? I'm at the point where I'm almost ready to move these methods out of the trait for the sake of retaining this gtk-inspired look and feel.