MeshFieldLinear represents a continuous piecewise-linear scalar field f
defined on a (triangular or tetrahedral) mesh; the field value changes linearly within each element E (triangle or tetrahedron), and the gradient ∇f is constant within each element.
The field is continuous across adjacent elements, but its gradient is discontinuous from one element to the other.
To represent a piecewise linear field f, we store one field value per vertex of the mesh. Each element E (triangle or tetrahedron) has (d+1) vertices, where d is the dimension of the element. For triangle, d = 2, and for tetrahedron, d = 3.
On each element E, we define a linear function fᵉ:ℝ³→ℝ using the field values at vertices of E. The gradient ∇fᵉ:ℝ³→ℝ³ is a constant map, so we write ∇fᵉ for the constant gradient vector on E as well. For a point Q in element E, we have:
f(Q) = fᵉ(Q) for Q ∈ E, ∇f(Q) = ∇fᵉ for Q ∈ E.
Notice that the domain of fᵉ is the entire space of ℝ³, while the domain of f is the underlying space of the mesh.
The following sections are details for interested readers.
For a linear triangle or tetrahedron element E in 3-D, we use barycentric coordinate:
(b₀, b₁, b₂) for triangle, (b₀, b₁, b₂, b₃) for tetrahedron, ∑bᵢ = 1, bᵢ ≥ 0,
to identify a point Q that lies in the simplicial element E. The coefficient bᵢ is the weight of vertex Vᵉᵢ of the element E, where the index i is a local index within the element E, not the global index of the entire mesh. In other words, vertex Vᵉᵢ is the iᵗʰ vertex of E, not the iᵗʰ vertex among all vertices in the mesh. The point Q in E can be expressed as:
Q = ∑bᵉᵢ(Q)Vᵉᵢ,
where we indicate the barycentric coordinate of a point Q on an element E as bᵉᵢ(Q).
At a point Q in element E, the piecewise linear field f has value:
f(Q) = fᵉ(Q) = ∑bᵉᵢ(Q)Fᵉᵢ
where Fᵉᵢ is the field value at the iᵗʰ vertex of element E.
A MeshFieldLinear is a frame-dependent quantity. Instances of a field should be named, as with any other frame-dependent quantity, with a trailing _F indicating the field's frame F. The field's frame is implicitly defined to be the same as the mesh's frame on which the field is instantiated. The field's frame affects two APIs:
The field (along with its corresponding mesh) can be transformed into a new frame by invoking the TransformVertices() method on the mesh and Transform() on the field, passing the same math::RigidTransform to both.
Consider each bᵉᵢ:ℝ³→ℝ as a linear function, its gradient ∇bᵉᵢ:ℝ³→ℝ³ is a constant map, and we write ∇bᵉᵢ for the constant gradient vector. The gradient of the piecewise linear field f at a point Q in an element E is:
∇f(Q) = ∇fᵉ = ∑Fᵉᵢ∇bᵉᵢ.
At a point Q in element E, the piecewise linear field f has value:
f(Q) = ∇fᵉ⋅Q + fᵉ(0,0,0).
Notice that (0,0,0) may or may not lie in element E.
T | a valid Eigen scalar for field values. |
MeshType | the type of the meshes: TriangleSurfaceMesh or VolumeMesh. |
#include <drake/geometry/proximity/mesh_field_linear.h>
Public Member Functions | |
MeshFieldLinear (std::vector< T > &&values, const MeshType *mesh, MeshGradientMode gradient_mode=MeshGradientMode::kOkOrThrow) | |
Constructs a MeshFieldLinear. More... | |
MeshFieldLinear (std::vector< T > &&values, const MeshType *mesh, std::vector< Vector3< T >> &&gradients) | |
(Advanced) Constructor variant which receives the pre-computed, per-element gradients of the field. More... | |
bool | is_gradient_field_degenerate () const |
const T & | EvaluateAtVertex (int v) const |
Evaluates the field value at a vertex. More... | |
template<typename B > | |
promoted_numerical_t< B, T > | Evaluate (int e, const typename MeshType::template Barycentric< B > &b) const |
Evaluates the field value at a location on an element. More... | |
template<typename C > | |
promoted_numerical_t< C, T > | EvaluateCartesian (int e, const Vector3< C > &p_MQ) const |
Evaluates the field at a point Qp on an element. More... | |
Vector3< T > | EvaluateGradient (int e) const |
Evaluates the gradient in the domain of the element indicated by e . More... | |
void | Transform (const math::RigidTransform< typename MeshType::ScalarType > &X_NM) |
(Advanced) Transforms this mesh field to be measured and expressed in frame N (from its original frame M). More... | |
std::unique_ptr< MeshFieldLinear > | CloneAndSetMesh (const MeshType *new_mesh) const |
Copy to a new MeshFieldLinear and set the new MeshFieldLinear to use a new compatible mesh. More... | |
const MeshType & | mesh () const |
const std::vector< T > & | values () const |
bool | Equal (const MeshFieldLinear< T, MeshType > &field) const |
Checks to see whether the given MeshFieldLinear object is equal via deep exact comparison. More... | |
Implements MoveConstructible, MoveAssignable | |
To copy a MeshFieldLinear, use CloneAndSetMesh(). | |
MeshFieldLinear (MeshFieldLinear &&)=default | |
MeshFieldLinear & | operator= (MeshFieldLinear &&)=default |
|
default |
MeshFieldLinear | ( | std::vector< T > && | values, |
const MeshType * | mesh, | ||
MeshGradientMode | gradient_mode = MeshGradientMode::kOkOrThrow |
||
) |
Constructs a MeshFieldLinear.
values | The field value at each vertex of the mesh. |
mesh | The mesh M to which this field refers. |
gradient_mode | Whether to calculate gradient field, and how to report failures. Calculating gradient allows EvaluateCartesian() to evaluate the field directly instead of converting Cartesian coordinates to barycentric coordinates first. If no gradient is calculated, EvaluateCartesian() will be slower. On the other hand, calculating gradient requires certain quality from mesh elements. If the mesh quality is very poor, calculating gradient may either throw or mark the gradient field as degenerate. See is_gradient_field_degenerate(). The default is to succeed or throw. |
You can use the parameter gradient_mode
to trade time and space of this constructor for speed of EvaluateCartesian(). For gradient_mode
!= kNone
(kOkOrThrow
by default, or kOkOrMarkDegenerate
similarly) and good mesh quality, this constructor will take longer time to compute and will store one field-gradient vector for each element in the mesh, but the interpolation by EvaluateCartesian() will be faster because we will use a dot product with the Cartesian coordinates directly, instead of solving a linear system to convert Cartesian coordinates to barycentric coordinates first.
When gradient_mode
!= kNone
and gradient calculation succeeds, EvaluateGradient() on a mesh element will be available. Otherwise, EvaluateGradient() will throw
.
The following features are independent of the choice of gradient_mode
.
gradient_mode
!= kNone
, a poor quality element can cause numerical errors in calculating field gradients. A poor quality element is defined as having an extremely large aspect ratio R=E/h, where E is the longest edge length and h is the shortest height. A height of a triangular element is the distance between a vertex and its opposite edge. A height of a tetrahedral element is the distance between a vertex and its opposite triangular face. For example, an extremely skinny triangle has poor quality, and a tetrahedron with four vertices almost co-planar also has poor quality. The exact threshold of the acceptable aspect ratio depends on many factors including the underlying scalar type and the exact shape and size of the element; however, a rough conservative estimation is 1e12.mesh
is non-null, and the number of entries in values
is the same as the number of vertices of the mesh. MeshFieldLinear | ( | std::vector< T > && | values, |
const MeshType * | mesh, | ||
std::vector< Vector3< T >> && | gradients | ||
) |
(Advanced) Constructor variant which receives the pre-computed, per-element gradients of the field.
gradients[i]
is the gradient of the linear function defined on the ith element of mesh
.
The caller is responsible for making sure that the gradients are consistent with the field values
defined at the vertices. Failure to do so will lead to nonsensical results when evaluating the field near a mesh vertex as opposed to at the vertex.
As with the other constructor, mesh
must remain alive at least as long as this field instance.
std::unique_ptr<MeshFieldLinear> CloneAndSetMesh | ( | const MeshType * | new_mesh | ) | const |
Copy to a new MeshFieldLinear and set the new MeshFieldLinear to use a new compatible mesh.
MeshFieldLinear needs a mesh to operate; however, MeshFieldLinear does not own the mesh. In fact, several MeshFieldLinear objects can use the same mesh.
bool Equal | ( | const MeshFieldLinear< T, MeshType > & | field | ) | const |
Checks to see whether the given MeshFieldLinear object is equal via deep exact comparison.
The name of the objects are exempt from this comparison. NaNs are treated as not equal as per the IEEE standard.
field | The field for comparison. |
true
if the given field is equal. promoted_numerical_t<B, T> Evaluate | ( | int | e, |
const typename MeshType::template Barycentric< B > & | b | ||
) | const |
Evaluates the field value at a location on an element.
The return type depends on both the field's scalar type T
and the Barycentric coordinate type B
. See promoted_numerical_t for details.
e | The index of the element. |
b | The barycentric coordinates. |
std::exception | if MeshType doesn't support Barycentric coordinates. |
B | The scalar type for the barycentric coordinate. |
const T& EvaluateAtVertex | ( | int | v | ) | const |
Evaluates the field value at a vertex.
v | The index of the vertex. |
promoted_numerical_t<C, T> EvaluateCartesian | ( | int | e, |
const Vector3< C > & | p_MQ | ||
) | const |
Evaluates the field at a point Qp on an element.
If the element is a tetrahedron, Qp is the input point Q. If the element is a triangle, Qp is the projection of Q on the triangle's plane.
If gradients have been calculated, it evaluates the field value directly. Otherwise, it converts Cartesian coordinates to barycentric coordinates for barycentric interpolation.
The return type depends on both the field's scalar type T
and the Cartesian coordinate type C
. See promoted_numerical_t for details.
e | The index of the element. |
p_MQ | The position of point Q expressed in frame M, in Cartesian coordinates. M is the frame of the mesh. |
std::exception | if the field does not have gradients defined and the MeshType doesn't support Barycentric coordinates. |
Evaluates the gradient in the domain of the element indicated by e
.
The gradient is a vector in R³ expressed in frame M. For surface meshes, it will particularly lie parallel to the plane of the corresponding triangle.
std::exception | if the gradient vector was not calculated. |
std::exception | if the gradient field is marked degenerate. |
bool is_gradient_field_degenerate | ( | ) | const |
const MeshType& mesh | ( | ) | const |
|
default |
void Transform | ( | const math::RigidTransform< typename MeshType::ScalarType > & | X_NM | ) |
(Advanced) Transforms this mesh field to be measured and expressed in frame N (from its original frame M).
See the class documentation for further details.
const std::vector<T>& values | ( | ) | const |