Loading [MathJax]/extensions/tex2jax.js
Tatooine
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Modules Pages Concepts
Rectilinear Grid

Basic usage

auto create_uniform_rectilinear_grid_2d() {
auto uniform_rectilinear_grid_2d = tatooine::rectilinear_grid{32, 64};
// uniform_rectilinear_grid_2d is of type
// tatooine::rectilinear_grid<tatooine::linspace<double>,
// tatooine::linspace<double>>
// ...
}
Definition: rectilinear_grid.h:38

This creates a 2-dimensional uniform rectilinear grid with resultion 32x64. It is in the domain [0,0]x[1,1];

tatooine::rectilinear_grid is a templated class and for each dimension holds a container of coordinates. When giving the constructor integral types (that must be > 0) a deduction guide will be used to create an object of type tatooine::rectilinear_grid<tatooine::linspace<double>, tatooine::linspace<double>>. So in the example above uniform_rectilinear_grid_2d holds two instances of tatooine::linspace<double>. The code above creates the following as here:

auto create_uniform_rectilinear_grid_2d() {
auto uniform_rectilinear_grid_2d = tatooine::rectilinear_grid {
tatooine::linspace{0.0, 1.0, 32},
tatooine::linspace{0.0, 1.0, 64}};
// ...
}
Definition: linspace.h:26

Candidates for other containers describing dimensions are std::vector and std::array . These types can also be mixed.

auto create_uniform_rectilinear_grid_2d() {
auto nonuniform_rectilinear_grid_3d = tatooine::rectilinear_grid{
linspace{0.0, 1.0, 3},
std::array{0.0, 0.9, 1.0},
std::vector{0.5, 0.6, 1.0}};
// nonuniform_rectilinear_grid_3d is of type
// tatooine::rectilinear_grid<tatooine::linspace<double>,
// std::array<double, 3>,
// std::vector<double>>
// ...
}

This code creates a three-dimensional rectilinear_grid that is described by three dimensions of mixed types. If possible tatooine::linspace should be taken because here the factors for differentiating do not have to be calculated.

Vertex Positions

Indexing

A tatooine::rectilinear_grid can be indexed with the parantheses-operator or the at method:

auto create_grid_with_vertex_property() {
auto uniform_rectilinear_grid_2d = tatooine::rectilinear_grid {32, 64};
auto const x_0_0 = uniform_rectilinear_grid_2d.vertex_at(0, 0); // == tatooine::vec{0.0, 0.0} in this example
auto const x_31_63 = uniform_rectilinear_grid_2d.at(31, 63);// == tatooine::vec{1.0, 1.0} in this example
}
auto vertex_at(std::index_sequence< DIs... >, std::array< Int, num_dimensions()> const &is) const -> vec< real_type, num_dimensions()>
Definition: rectilinear_grid.h:640

These methods return a tatooine::vec that represents the position of the rectilinear_grid index.

Iterating over vertices

One can iterate in two ways over the vertices of a tatooine::rectilinear_grid:

auto iterate_over_vertex_positions() {
auto uniform_rectilinear_grid_2d = tatooine::rectilinear_grid{32, 64};
for (auto const x : uniform_rectilinear_grid_2d.vertices()) {
// x is an instance tatooine::vec
}
}
auto iterate_over_vertex_indices() {
auto uniform_rectilinear_grid_2d = tatooine::rectilinear_grid{32, 64};
uniform_rectilinear_grid_2d.vertices().iterate_indices([&](auto const... indices){
auto const x = uniform_rectilinear_grid_2d.vertex_at(indices...);
});
}
auto vertices() const
Definition: rectilinear_grid.h:637

Vertex Properties

For storing properties of arbitrary types type erasure is used.

Inserting Properties

Instances of tatooine::rectilinear_grid can be equipped with vertex properties that can hold any data type. Vertex properties can be created as in the following example:

auto create_grid_with_vertex_property() {
auto uniform_rectilinear_grid_2d = tatooine::rectilinear_grid{32, 64};
auto& prop = uniform_rectilinear_grid_2d.vertex_property<double>("property_name");
prop(11, 63) = 42.1337;
}
auto vertex_property(std::string const &name) -> typed_vertex_property_interface_type< T, HasNonConstReference > &
Definition: rectilinear_grid.h:831
Note
prop has to be a reference! Otherwise you are working on a copy of the property.

uniform_rectilinear_grid_2d now holds a vertex property called "property_name". Internally the method vertex_property creates an object whose type inherits tatooine::dynamic_multidim_array.

If vertex_prop is called again with the same name and the same type you will get a reference to same property.

If vertex_prop is called again with the same name and the another type an exception is thrown.

When calling vertex_prop with a name that has not been used before tatooine::rectilinear_grid::insert_vertex_property is called which then calls tatooine::rectilinear_grid::insert_contiguous_vertex_property. Hence the following code produces the same when "property_name" has not been used before as an argument on that grid:

auto create_grid_with_contiguous_vertex_property() {
auto uniform_rectilinear_grid_2d = tatooine::rectilinear_grid{32, 64};
auto& prop = uniform_rectilinear_grid_2d.insert_contiguous_vertex_property<double>("property_name");
prop(11, 63) = 42.1337;
}
auto insert_contiguous_vertex_property(std::string const &name) -> auto &
Definition: rectilinear_grid.h:789

So these functions create containers that keep their memory in linear memory. There is also a function that creates memory that is chunked:

auto create_grid_with_chunked_vertex_property() {
auto uniform_rectilinear_grid_2d = tatooine::rectilinear_grid {32, 64};
auto& prop = uniform_rectilinear_grid_2d.insert_chunked_vertex_property<double>("property_name", 2, 2);
prop(11, 63) = 42.1337;
}
auto insert_chunked_vertex_property(std::string const &name, std::vector< std::size_t > const &chunk_size) -> auto &
Definition: rectilinear_grid.h:796

With this the data of prop is stored in 2x2 blocks in memory to ensure a spatial memory coherence.

If the property already exists and another container type is queried to use an exception will be thrown. Example:

auto create_chunked_and_contiguous_vertex_property() {
auto uniform_rectilinear_grid_2d = tatooine::rectilinear_grid{32, 64};
auto& chunked_uv = uniform_rectilinear_grid_2d.insert_chunked_vertex_property<tatooine::vec2>("uv", 2, 2);
auto& contiguous_uv = uniform_rectilinear_grid_2d.insert_contiguous_vertex_property<tatooine::vec2>("uv"); // here a std::runtime_error will be thrown
}
Definition: vec.h:12

Query Properties

Because the internal type is hidden by "type erasure" one has to specify the type again as template parameter when querying a property.

template <typename... Dimensions>
auto query_grid_property(tatooine::rectilinear_grid<Dimensions...> const& g) {
auto& property = g.vertex_property<double>("property_name");
}

The function above receives a rectilinear_grid with an arbitrary number of dimensions with arbitrary types.

An exception will be thrown if no property with name "property_name" can be found or if a property can be found but the specified and the stored types do not match.

There are some helper methods to make the code more readable or at least to hide templates:

auto create_a_rectilinear_grid_and_some_props() {
auto g = tatooine::rectilinear_grid{64, 64};
// create a vertex property that holds tatooine::real_type instances per vertex
auto& scalar_prop = g.scalar_vertex_property("scalar_prop");
// create a vertex property that holds vec2 instances per vertex
auto& vec2_prop = g.vec2_vertex_property("vec2_prop");
// create a vertex property that holds vec2 instances per vertex
auto& vec3_prop = g.vec3_vertex_property("vec3_prop");
// create a vertex property that holds vec2 instances per vertex
auto& mat4_prop = g.mat4_vertex_property("mat4_prop");
}
auto scalar_vertex_property(std::string const &name) const -> auto const &
Definition: rectilinear_grid.h:868

Sampling Properties

A property can be sampled like that:

auto sample_grid_property() {
auto g = tatooine::rectilinear_grid{32, 64};
auto& property = g.scalar_vertex_property("property_name");
// ...
// Create the property data.
// ...
// Do not use a reference here.
auto sampler = property.sampler();
auto const sample = sampler(0.5, 0.5);
}
Note
tatooine::typed_grid_vertex_property_interface::sampler returns an object of type tatooine::grid_vertex_property that stores a reference to its corresponding tatooine::rectilinear_grid and a reference to the property so one must not use a reference!

The returned object is derived by tatooine::field so every available algorithm can be applied the the sampler.

The tatooine::rectilinear_grid::sampler method is a template function that can get interpolation kernels as template parameters. By default cubic interpolation kernels are used for every dimension. So the following code produces the same results as the code above.

auto sample_grid_property() {
auto g = tatooine::rectilinear_grid{32, 64};
auto& property = g.scalar_vertex_property("property_name");
// ...
auto sampler = property.sampler<interpolation::cubic>();
auto const sample = sampler(0.5, 0.5);
}

One can also mix interpolation kernels:

auto sample_grid_property() {
auto g = tatooine::rectilinear_grid{32, 64};
auto& property = g.scalar_vertex_property("property_name");
// ...
auto sampler = property.sampler<tatooine::interpolation::linear,
auto const sample = sampler(0.5, 0.5);
}
Definition: interpolation.h:216
Definition: interpolation.h:16

Here the sampler interpolates linearly in the first dimension and cubicly in the second dimension.