pub trait BaseShape {
    const EDGES: usize;

    fn initial_points(&self) -> Vec<Vec3A>;
    fn triangles(&self) -> Box<[Triangle]>;
    fn interpolate(&self, a: Vec3A, b: Vec3A, p: f32) -> Vec3A;

    fn interpolate_half(&self, a: Vec3A, b: Vec3A) -> Vec3A { ... }
    fn interpolate_multiple(
        &self,
        a: Vec3A,
        b: Vec3A,
        indices: &[u32],
        points: &mut [Vec3A]
    ) { ... } }
Expand description

Defines the setup for a base shape, and the functions used in interpolation.

If you want to use a different interpolation function, implement this trait for a new type, and carry over only the properties you’d like to keep:

use hexasphere::{Triangle, shapes::IcoSphereBase};
use glam::Vec3A;
// Uses linear interpolation instead of spherical.
struct FlatIcosahedron;

impl BaseShape for FlatIcosahedron {
    // Keep the initial parameters.
    fn initial_points(&self) -> Vec<Vec3A> {
        IcoSphereBase.initial_points()
    }

    fn triangles(&self) -> Box<[Triangle]> {
        IcoSphereBase.triangles()
    }
    const EDGES: usize = IcoSphereBase::EDGES;

    // Swap out what you'd like to change.
    fn interpolate(&self, a: Vec3A, b: Vec3A, p: f32) -> Vec3A {
        hexasphere::interpolation::lerp(a, b, p)
    }

    fn interpolate_half(&self, a: Vec3A, b: Vec3A) -> Vec3A {
        hexasphere::interpolation::lerp_half(a, b)
    }

    fn interpolate_multiple(&self, a: Vec3A, b: Vec3A, indices: &[u32], points: &mut [Vec3A]) {
        hexasphere::interpolation::lerp_multiple(a, b, indices, points);
    }
}

Or, create your own shape, by changing the values for initial_points, triangles, and EDGES. Check the documentation for these members individually on how they should be implemented.

Required Associated Constants

Number of unique edges defined in the contents of triangles(). This number is 5 for a square for example:

a - 0 - b
|     / |
3   4   1
| /     |
d - 2 - c

Required Methods

The initial vertices for the triangle. Note that Vec3A::new is not a const fn(), hence I recommend you use lazy_static. Check the source file for this crate and look for the constants module at the bottom for an example.

Constraints on the points depend on the interpolation function used:

  • slerp requires normalized (magnitude 1) data.
  • lerp doesn’t care.
  • normalized_lerp requires normalized (magnitude 1) data.

Base triangles for the shape.

  • The fields a, b, and c define the indices for the points of the triangles given the data present in initial_points. Note that this crate assumes points are in a counter clockwise ordering.
  • The fields ab_edge, bc_edge, ca_edge mark the index of the edge which a/b, b/c, and c/a border respectively. While theoretically you could give each triangle its own edge, minimizing edges saves on memory footprint and performance.
  • Triangles should be created through Triangle::new.

Basic function used for interpolation. When p is 0.0, a is expected. When p is 1.0, b is expected. There are three options already implemented in this crate:

  • lerp implements linear interpolation.
  • geometric_slerp implements spherical interpolation. (Interpolates along an arc on a sphere)
  • normalized_lerp implements cheaper yet less accurate spherical interpolation. The accuracy decreases as the angle between the two points on the unit sphere increases.

Provided Methods

If an optimization is available for the case where p is 0.5, this function should implement it. This defaults to calling interpolate(a, b, 0.5) however.

If an optimization is available for the case where p varies but a and b don’t this function should implement it.

Parameters
  • a: start.
  • b: end.
  • indices: list of indices to index into points. points at the index should contain the result. The index (n) of an index should correspond with the nth point in a distribution of indices.len() points between (exclusive) a and b.
  • points: list of points where the results of the calculation should end up. To be indexed by values in indices.

Implementors