elrnv / vtkio

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

creating a Circle approximated by a BezierCurve #17

Closed JHenneberg closed 3 years ago

JHenneberg commented 3 years ago

I am struggling creating a BezierCurve. Could you give me an example how this is done?

elrnv commented 3 years ago

Thank you for the question! As far as I can tell Curve cells are relatively new in VTK and so there aren't many examples in the wild. Though after digging through their documentation and examples, I discovered that you need a "RationalWeights" attribute for bezier curves. So something like the following should create a valid VTK file:

Vtk {
    version: Version { major: 4, minor: 2 },
    title: String::new(),
    byte_order: ByteOrder::BigEndian,
    file_path: None,
    data: DataSet::inline(UnstructuredGridPiece {
        points: IOBuffer::F64(vec![
            // coordinates of node 0
            0.0, 1.0, 0.0, // coordinates of node 1
            1.0, 0.0, 0.0, // coordinates of node 2
            1.0, 1.0, 0.0,
        ]),
        cells: Cells {
            cell_verts: VertexNumbers::Legacy {
                // Number of Bezier curves.
                num_cells: 1,
                // Vertices for each curve.
                vertices: vec![3, 0, 1, 2],
            },
            types: vec![CellType::BezierCurve],
        },
        data: Attributes {
            point: vec![Attribute::DataArray(DataArray {
                name: "RationalWeights".to_string(),
                elem: ElementType::Scalars {
                    num_comp: 1,
                    lookup_table: None,
                },
                data: vec![1.0f64, 1.0, 2.0f64.sqrt() / 2.0].into(),
            })],
            ..Default::default()
        },
    }),
}

For some references, there is a writeup about bezier curves used in VTK here and some example C++ code here which can be compiled and run to produce some .vtu examples. Here is one of a quadratic bezier generated by that code:

<?xml version="1.0"?>
<VTKFile type="UnstructuredGrid" version="0.1" byte_order="LittleEndian" header_type="UInt32" compressor="vtkZLibDataCompressor">
  <UnstructuredGrid>
    <Piece NumberOfPoints="3" NumberOfCells="1">
      <PointData RationalWeights="RationalWeights">
        <DataArray type="Float64" Name="RationalWeights" format="ascii" RangeMin="0.7071067811865476" RangeMax="1">
          1 1 0.7071067811865476
        </DataArray>
      </PointData>
      <CellData>
      </CellData>
      <Points>
        <DataArray type="Float32" Name="Points" NumberOfComponents="3" format="ascii" RangeMin="1" RangeMax="1.4142135623730951">
          0 1 0 1 0 0
          1 1 0
          <InformationKey name="L2_NORM_RANGE" location="vtkDataArray" length="2">
            <Value index="0">
              1
            </Value>
            <Value index="1">
              1.4142135624
            </Value>
          </InformationKey>
        </DataArray>
      </Points>
      <Cells>
        <DataArray type="Int64" Name="connectivity" format="ascii" RangeMin="0" RangeMax="2">
          0 1 2
        </DataArray>
        <DataArray type="Int64" Name="offsets" format="ascii" RangeMin="3" RangeMax="3">
          3
        </DataArray>
        <DataArray type="UInt8" Name="types" format="ascii" RangeMin="75" RangeMax="75">
          75
        </DataArray>
      </Cells>
    </Piece>
  </UnstructuredGrid>
</VTKFile>

It seems that these don't appear smooth in paraview though unfortunately. That may be a good question for the Kitware folks :)

Hope this helps and good luck!

Andlon commented 3 years ago

It seems that these don't appear smooth in paraview though unfortunately. That may be a good question for the Kitware folks :)

Yeah this is not so obvious, but there's a way to make them "arbitrarily" smooth. You need to toggle on "Advanced Properties" for the object. Then you'll find an option called "Nonlinear Subdivision Level". This will basically recursively split the curve into more straight segments for rendering. With a sufficiently high enough value it renders as a reasonably smooth curve. Still a far cry from actual curved rendering, but it's much better than nothing :shrug:

JHenneberg commented 3 years ago

Thank you. I will give it a try. I have to realize that the documentation of VTK is quite rudimentary or hard to find (I am not talking about the doxygen documentation).

I am willing to start to provide examples for each CellType in this repository. If this is something wanted I would create an issue where we could discuss further details.

JHenneberg commented 3 years ago

Thank you for the question! As far as I can tell Curve cells are relatively new in VTK and so there aren't many examples in the wild. Though after digging through their documentation and examples, I discovered that you need a "RationalWeights" attribute for bezier curves. So something like the following should create a valid VTK file:

Vtk {
    version: Version { major: 4, minor: 2 },
    title: String::new(),
    byte_order: ByteOrder::BigEndian,
    file_path: None,
    data: DataSet::inline(UnstructuredGridPiece {
        points: IOBuffer::F64(vec![
            // coordinates of node 0
            0.0, 1.0, 0.0, // coordinates of node 1
            1.0, 0.0, 0.0, // coordinates of node 2
            1.0, 1.0, 0.0,
        ]),
        cells: Cells {
            cell_verts: VertexNumbers::Legacy {
                // Number of Bezier curves.
                num_cells: 1,
                // Vertices for each curve.
                vertices: vec![3, 0, 1, 2],
            },
            types: vec![CellType::BezierCurve],
        },
        data: Attributes {
            point: vec![Attribute::DataArray(DataArray {
                name: "RationalWeights".to_string(),
                elem: ElementType::Scalars {
                    num_comp: 1,
                    lookup_table: None,
                },
                data: vec![1.0f64, 1.0, 2.0f64.sqrt() / 2.0].into(),
            })],
            ..Default::default()
        },
    }),
}

For some references, there is a writeup about bezier curves used in VTK here and some example C++ code here which can be compiled and run to produce some .vtu examples. Here is one of a quadratic bezier generated by that code:

<?xml version="1.0"?>
<VTKFile type="UnstructuredGrid" version="0.1" byte_order="LittleEndian" header_type="UInt32" compressor="vtkZLibDataCompressor">
  <UnstructuredGrid>
    <Piece NumberOfPoints="3" NumberOfCells="1">
      <PointData RationalWeights="RationalWeights">
        <DataArray type="Float64" Name="RationalWeights" format="ascii" RangeMin="0.7071067811865476" RangeMax="1">
          1 1 0.7071067811865476
        </DataArray>
      </PointData>
      <CellData>
      </CellData>
      <Points>
        <DataArray type="Float32" Name="Points" NumberOfComponents="3" format="ascii" RangeMin="1" RangeMax="1.4142135623730951">
          0 1 0 1 0 0
          1 1 0
          <InformationKey name="L2_NORM_RANGE" location="vtkDataArray" length="2">
            <Value index="0">
              1
            </Value>
            <Value index="1">
              1.4142135624
            </Value>
          </InformationKey>
        </DataArray>
      </Points>
      <Cells>
        <DataArray type="Int64" Name="connectivity" format="ascii" RangeMin="0" RangeMax="2">
          0 1 2
        </DataArray>
        <DataArray type="Int64" Name="offsets" format="ascii" RangeMin="3" RangeMax="3">
          3
        </DataArray>
        <DataArray type="UInt8" Name="types" format="ascii" RangeMin="75" RangeMax="75">
          75
        </DataArray>
      </Cells>
    </Piece>
  </UnstructuredGrid>
</VTKFile>

It seems that these don't appear smooth in paraview though unfortunately. That may be a good question for the Kitware folks :)

Hope this helps and good luck!

The CellType::Bezier* or CellType::Lagrange* are not documented on the official kitware documentation only on in the javascript version

It seems that these don't appear smooth in paraview though unfortunately. That may be a good question for the Kitware folks :)

Yeah this is not so obvious, but there's a way to make them "arbitrarily" smooth. You need to toggle on "Advanced Properties" for the object. Then you'll find an option called "Nonlinear Subdivision Level". This will basically recursively split the curve into more straight segments for rendering. With a sufficiently high enough value it renders as a reasonably smooth curve. Still a far cry from actual curved rendering, but it's much better than nothing 🤷

I read this aswell in the report but how can I add this "Advanced Propertie" is not described. Analysing the rust struct there is no data type AdvancedProperties or other clue. Or is it smth like this:

data: Attributes {
    point: vec![Attribute::DataArray(DataArray {
        name: "NonlinearSubdivsionLevel".to_string(),
        elem: ElementType::Scalars {
            num_comp: 1,
            lookup_table: None,
        },
        data: vec![10.0f64].into(),
    })],
    ..Default::default()
},
Andlon commented 3 years ago

I read this aswell in the report but how can I add this "Advanced Propertie" is not described. Analysing the rust struct there is no data type AdvancedProperties or other clue.

Sorry, I was not clear. This is something you need to toggle in ParaView in order for it to subdivide your curve and render it with higher resolution than the default (which draws it as a linear segment). See attached picture below!

paraview_advanced_properties

EDIT: The curve on the right here is the .vtu file that Egor provided above.

JHenneberg commented 3 years ago

I read this aswell in the report but how can I add this "Advanced Propertie" is not described. Analysing the rust struct there is no data type AdvancedProperties or other clue.

Sorry, I was not clear. This is something you need to toggle in ParaView in order for it to subdivide your curve and render it with higher resolution than the default (which draws it as a linear segment). See attached picture below!

paraview_advanced_properties

EDIT: The curve on the right here is the .vtu file that Egor provided above.

Ok. It works. So this is just a rendering option and can not be embeeded in the *.vtu

elrnv commented 3 years ago

Yeah this is not so obvious, but there's a way to make them "arbitrarily" smooth. You need to toggle on "Advanced Properties" for the object. Then you'll find an option called "Nonlinear Subdivision Level". This will basically recursively split the curve into more straight segments for rendering. With a sufficiently high enough value it renders as a reasonably smooth curve. Still a far cry from actual curved rendering, but it's much better than nothing shrug

Thank you for that! I should read the docs I reference :P

Ok. It works. So this is just a rendering option and can not be embeeded in the *.vtu

Yes exactly.

I am willing to start to provide examples for each CellType in this repository. If this is something wanted I would create an issue where we could discuss further details.

I would love that, thank you! I agree that docs on this seem to be somewhat sparse, and it is not always clear from the C++ code how these files should be structured since the API is not as close to the file format as the Rust structs IMO. So I think this would be of great help!

Closing this since this particular question seems to be resolved.