Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

load into Vec3r struct from ply #2

Closed

Conversation

rezural
Copy link
Contributor

@rezural rezural commented Dec 5, 2020

This adds loading into structs directly from ply-rs.

as per your suggestions from #1.

Couple of things:
You may want me to pull the ply stuff out into a submodule, which I can do.
I may not have been using the repr(transparent) properly, I still had to access the inner struct through .0, so I have left that commented out for now.

This has to map from Vec<Vec3r> to Vec<Vector3<R>> manually, so I'm not sure if I'm doing this right.

Any advice welcome...

Thanks!

@w1th0utnam3
Copy link
Member

Well, the trick is to use some unsafe code that we know is actually safe. When you annotate a type with #[repr(transparent)] this means that the new type is represented in memory exactly the same as the inner type. For details, see e.g. https://doc.rust-lang.org/1.26.2/unstable-book/language-features/repr-transparent.html. This allows us on one hand to implement traits and methods on the new type (like you did), but it also allows us to just view instances of the new type as instances of the inner type. This is done by transmuting (like casting without conversion in other languages). In our case, this would be

// This is safe, because we defined Vec3r<R> as transparent over Vector3<R>
let particles = unsafe { std::mem::transmute::<Vec<Vec3r<R>>, Vec<Vector3<R>>>(particles_ply) };

(we could drop the explicit type arguments on transmute and let type-inference figure it out, but the explicit arguments ensure that we don't accidentally transmute to a wrong type when refactoring)
In the end, the transmute is a no-op and saves us copying and manually converting each individual element.

However, for this to work, your Vec3r definition is missing R: Real as generic argument, which should also be the type used by the Vector3 (because this is the type returned by the particles_from_ply function). So the type definition would be

#[repr(transparent)]
struct Vec3r<R: Real>(Vector3<R>);

and you would have to slightly adapt your trait implementation.

Do you want to make these changes?

@w1th0utnam3
Copy link
Member

Ah, and yes, it would probably make sense to modularize the IO stuff more (maybe move it to the lib) and add some unit tests with sample files, but I don't want to get into this right now.

@w1th0utnam3
Copy link
Member

w1th0utnam3 commented Dec 5, 2020

Whoops, made a mistake. The unsafe code actually has to be

    // Convert the particle vector from `Vec<Vec3r<R>>` to `Vec<Vector3<R>>`
    let particles = unsafe {
        // Ensure the original vector is not dropped
        let mut particles = std::mem::ManuallyDrop::new(particles_ply);
        // Construct the new vector by converting the data pointer
        Vec::from_raw_parts(
            // This is safe, because we defined Vec3r<R> transparent over Vector3<R>
            particles.as_mut_ptr() as *mut Vector3<R>,
            particles.len(),
            particles.capacity(),
        )
    };

because you are only allowed to transmute the actual data of the Rust Vec, not the Vec itself. See the Vec example here and the comment here.

@rezural
Copy link
Contributor Author

rezural commented Dec 7, 2020

Hrm,

How about we leave it with the (non-idiomatic) approach for now?

I am thinking of solving this on the Ply-rs side, i.e. adding a data marshalling interface for when your types arent local (honestly most people will be using 3rd party structs for their 3d data?).

Cheers

@w1th0utnam3
Copy link
Member

Right, support for this in ply-rs itself would be much cleaner.

I'll add a few comments before merging.

@@ -167,3 +160,22 @@ pub fn to_binary_f32<R: Real, P: AsRef<Path>>(file: P, values: &[R]) -> Result<(

Ok(())
}

// #[repr(transparent)]
struct Vec3r(Vector3<f32>);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should rename this to Vec3f32 for now, because currently we only support reading PLY files with floats.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • you can remove the repr attribtute

Comment on lines +169 to +171
Self {
0: { Vector3::new(0.0, 0.0, 0.0) },
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a better default is to use NAN here? So that if properties are missing below, it is not as silent as it would be with zeros? Btw. you can write

Self(Vector3::repeat(std::f32::NAN))

let mut ply_file = std::io::BufReader::new(ply_file);

let vertex_parser = ply_rs::parser::Parser::<Vec3r>::new();
let header = vertex_parser.read_header(&mut ply_file).unwrap();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of unwrap

.context("Failed to read PLY header")?

@w1th0utnam3
Copy link
Member

Ok, I moved the file format stuff into submodules. You would have to move your changes into the ply_format module.

@rezural
Copy link
Contributor Author

rezural commented Dec 14, 2020

Hey,

I'll have a look at this soon, been moving around the last week, so it has been hard to get time at the computer..

Cheers!

@w1th0utnam3
Copy link
Member

No rush

@rezural
Copy link
Contributor Author

rezural commented Jun 4, 2021

So we should probably close this.

Apologies, it has been quite a long time ago.

IIRC I had a look into making it more idiomatic, but it was a PITA, and didnt make the code any clearer, or simpler.

Cheers

@w1th0utnam3 w1th0utnam3 force-pushed the master branch 4 times, most recently from a2e7640 to bfe4c19 Compare August 10, 2021 18:12
@w1th0utnam3 w1th0utnam3 added the enhancement New feature or request label Dec 16, 2021
@w1th0utnam3 w1th0utnam3 closed this Jul 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants