elrnv / vtkio

Visualization ToolKit (VTK) file parser and writer
Apache License 2.0
55 stars 12 forks source link

Extracting Data #16

Closed dwerner95 closed 1 year ago

dwerner95 commented 2 years ago

Hey All,

is there any way to extract data from a vtk data easily ? I couldn't find any evidence of a extraction method for the datasets into arrays. I tried to write a function myself, but now i am stuck making it generic for the different datatypes of IOBuffer and, to be honest, i have no idea what I am doing here, but it returns a array in the end.

use vtkio::model::*;
fn main() {
    let file = "test.vtk";
    let mut vtk_file = match Vtk::import(&file)
        .expect(&format!("Failed to load file: {:?}", file))
        .data
    {
        DataSet::PolyData { pieces, .. } => pieces,
        _ => panic!("OhOh"),
    };
    let data = &**match &vtk_file[0] {
        Piece::Inline(x) => x,
        _ => panic!("OhOh2"),
    };
    let x = &data.data.point[0];
    let y = match &x {
        Attribute::Field { name, data_array } => data_array,
        _ => panic!("OhOh3"),
    };
    let mut data: Option<&Vec<i32>> = None;
    for elem in y {
        if elem.name == "id" {
            data = Some(match &elem.data {
                IOBuffer::I32(vec) => vec,
                _ => panic!("OhOh4"),
            });
            break;
        }
    }
    let data = if let Some(data) = data {
        data
    } else {
        panic!("OhOh5")
    };
    println!("{:?}", data);
}

}

Is there any better way to do this?

elrnv commented 2 years ago

Thank you for the question! I think you have the gist of it. Sadly there aren't too many utilities in vtkio yet to make it convenient to extract specific data from a vtk file, though I'm not exactly sure what this API would look like. I expect it heavily depends on the use case since VTK spans many different ones.

Having said this, for IOBuffer specifically you can use the cast_into method to get your data into the format you like. or if you are sure about the type, you can use the into_vec method.

elrnv commented 2 years ago

I think also with a few rust tricks, you may get a slightly simpler version, but not by much:

fn get_id_field() -> Vec<i32> {
    let file = "test.vtk";
    let mut vtk_file = match Vtk::import(&file)
        .expect(&format!("Failed to load file: {:?}", file));
    let pieces = if let DataSet::UnstructuredGrid { pieces, .. } = vtk_file.data {
        pieces
    } else {
        panic!("Wrong vtk data type");
    };

    // If piece is already inline, this just returns a piece data clone.
    let piece = pieces[0].load_piece_data(None).expect("Failed to load piece data");

    let attribute = &piece.data.point[0];

    if let Attribute::Field { data_array, .. } = attribute {
         data_array
            .iter()
            .find(|&DataArrayBase { name, .. }| name == "id")
            .expect("Failed to find id field")
            .data
            .clone()
            .cast_into::<i32>()
            .expect("Failed cast")
    } else {
        panic!("No field attribute found");
    }
}

I hope this helps and thanks again for this question, I also realized that the clone before cast_into shouldn't be necessary, so I will simplify it in a next release!