mesh/mesh.h
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /// @file | ||
| 2 | /// @brief Triangle meshes, their measures, normals and rigid transforms. | ||
| 3 | #pragma once | ||
| 4 | |||
| 5 | #include "terraingen/util/geometry.h" | ||
| 6 | |||
| 7 | #include <array> | ||
| 8 | #include <cstdint> | ||
| 9 | #include <vector> | ||
| 10 | |||
| 11 | namespace terraingen { | ||
| 12 | |||
| 13 | /// A triangle mesh of shared vertices; triangles are counter-clockwise seen from outside, | ||
| 14 | /// so a closed mesh has a positive `Volume`. | ||
| 15 | struct TriangleMesh { | ||
| 16 | std::vector<Vec3d> positions; ///< Vertex positions. | ||
| 17 | std::vector<std::array<std::uint32_t, 3>> triangles; ///< Indices into `positions`. | ||
| 18 | }; | ||
| 19 | |||
| 20 | /// An axis-aligned box. | ||
| 21 | struct Box3d { | ||
| 22 | Vec3d min; ///< Lowest corner. | ||
| 23 | Vec3d max; ///< Highest corner. | ||
| 24 | |||
| 25 | /// The box's size along each axis, `max` - `min`. | ||
| 26 | 3735 | Vec3d Extents() const { | |
| 27 | 3735 | return max - min; | |
| 28 | } | ||
| 29 | }; | ||
| 30 | |||
| 31 | /// The smallest axis-aligned box around a mesh's vertices. | ||
| 32 | /// @throws std::invalid_argument for a mesh without vertices. | ||
| 33 | Box3d Bounds(const TriangleMesh& mesh); | ||
| 34 | |||
| 35 | /// Checks that every triangle indexes one of the mesh's vertices. | ||
| 36 | /// @throws std::invalid_argument for a triangle indexing past the vertices. | ||
| 37 | void ValidateMesh(const TriangleMesh& mesh); | ||
| 38 | |||
| 39 | /// The volume a closed mesh encloses, as a sum of signed tetrahedra from the origin; negative | ||
| 40 | /// when the triangles face inward. | ||
| 41 | /// @throws std::invalid_argument as `ValidateMesh`. | ||
| 42 | double Volume(const TriangleMesh& mesh); | ||
| 43 | |||
| 44 | /// The total area of a mesh's triangles. | ||
| 45 | /// @throws std::invalid_argument as `ValidateMesh`. | ||
| 46 | double SurfaceArea(const TriangleMesh& mesh); | ||
| 47 | |||
| 48 | /// The unit normal of each vertex: the area-weighted mean of its triangles' normals. | ||
| 49 | /// @throws std::invalid_argument as `ValidateMesh`. | ||
| 50 | std::vector<Vec3d> VertexNormals(const TriangleMesh& mesh); | ||
| 51 | |||
| 52 | /// A mesh with per-vertex normals, its vertices split along creases so fracture faces keep | ||
| 53 | /// hard edges while noisy surfaces stay smooth. | ||
| 54 | struct ShadedMesh { | ||
| 55 | TriangleMesh mesh; ///< The mesh, vertices split along creases. | ||
| 56 | std::vector<Vec3d> normals; ///< One per vertex of `mesh`. | ||
| 57 | }; | ||
| 58 | |||
| 59 | /// A mesh with its vertices split along creases and normals averaged, weighted by area, | ||
| 60 | /// over the triangles that meet within the crease angle. | ||
| 61 | /// @param creaseAngle The largest angle between triangle normals that is smoothed, in radians. | ||
| 62 | /// @throws std::invalid_argument for a negative or non-finite `creaseAngle`, or as | ||
| 63 | /// `ValidateMesh`. | ||
| 64 | ShadedMesh WithCreases(const TriangleMesh& mesh, double creaseAngle); | ||
| 65 | |||
| 66 | /// A rotation followed by a translation. | ||
| 67 | struct RigidTransform { | ||
| 68 | /// Row-major 3 x 3. | ||
| 69 | std::array<double, 9> rotation{1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0}; | ||
| 70 | /// Applied after the rotation. | ||
| 71 | Vec3d translation{}; | ||
| 72 | |||
| 73 | /// The point rotated, then translated. | ||
| 74 | Vec3d Apply(const Vec3d& point) const; | ||
| 75 | /// The transform that applies `first`, then this one. | ||
| 76 | RigidTransform After(const RigidTransform& first) const; | ||
| 77 | |||
| 78 | /// A rotation by `angle` radians about x, counter-clockwise looking down the axis. | ||
| 79 | static RigidTransform RotationX(double angle); | ||
| 80 | /// A rotation by `angle` radians about y, counter-clockwise looking down the axis. | ||
| 81 | static RigidTransform RotationY(double angle); | ||
| 82 | /// A rotation by `angle` radians about z, counter-clockwise looking down the axis. | ||
| 83 | static RigidTransform RotationZ(double angle); | ||
| 84 | /// A pure translation by `offset`. | ||
| 85 | static RigidTransform Translation(const Vec3d& offset); | ||
| 86 | }; | ||
| 87 | |||
| 88 | /// Checks that a matrix is a proper rotation: orthonormal to within 1e-9, without a | ||
| 89 | /// reflection. | ||
| 90 | /// @param rotation Row-major 3 x 3. | ||
| 91 | /// @throws std::invalid_argument otherwise. | ||
| 92 | void RequireRotation(const std::array<double, 9>& rotation); | ||
| 93 | |||
| 94 | /// The unit quaternion (x, y, z, w) of a proper rotation, row-major 3 x 3. | ||
| 95 | std::array<double, 4> RotationQuaternion(const std::array<double, 9>& rotation); | ||
| 96 | |||
| 97 | /// A mesh with every vertex moved by a transform. | ||
| 98 | TriangleMesh Transformed(const TriangleMesh& mesh, const RigidTransform& transform); | ||
| 99 | |||
| 100 | /// A mesh with every vertex scaled about the origin per axis; triangles flip when an odd | ||
| 101 | /// number of the factors are negative, so the mesh stays outward-facing. | ||
| 102 | /// @param scale The factor per axis, nonzero and finite. | ||
| 103 | /// @throws std::invalid_argument for a zero or non-finite factor. | ||
| 104 | TriangleMesh Scaled(const TriangleMesh& mesh, const Vec3d& scale); | ||
| 105 | |||
| 106 | } // namespace terraingen | ||
| 107 |