ianmackenzie/elm-triangular-mesh/1.0.0

NOTE: this package is not compatible with Elm 0.19.1

TriangularMesh

This module provides functions for working with indexed triangular meshes. You can:

  • Construct meshes from vertices and face indices
  • Extract vertices, faces and edges in various ways
  • Combine multiple meshes into a single mesh

Note that the Array type used by this package is the one from Array.Hamt, not Elm's built-in Array type.

type TriangularMesh vertex

A TriangularMesh is a simple form of face-vertex mesh defined by an array of vertices and a list of face indices. Each set of face indices consists of a tuple of three integer vertex indices.

The vertices themselves can be any type you want. For a simple 2D mesh, you might have each vertex be simply a point:

type alias Mesh =
    TriangularMesh Point2d

For a 3D mesh, each vertex might be a (point, normal) tuple:

type alias Mesh =
    TriangularMesh ( Point3d, Vector3d )

In more complex cases, each vertex might be a record:

type alias VertexData =
    { position : Point3d
    , normal : Vector3d
    , color : Color
    }


type alias Mesh =
    TriangularMesh VertexData

Constants

empty : TriangularMesh vertex

A mesh with no vertices or faces.

Constructors

indexed : Array vertex -> List ( Int, Int, Int ) -> TriangularMesh vertex

Create a mesh from an array of vertices and list of face indices. For example, to construct a square where a is the lower left corner, b is the lower right corner, c is the upper right corner and d is the upper left corner:

Square mesh

vertices =
    Array.fromList [ a, b, c, d ]


faceIndices =
    [ ( 0, 1, 2 ), ( 0, 2, 3 ) ]


square =
    TriangularMesh.indexed vertices faceIndices

Invalid face indices (triples where any one of the three indices is out of bounds) will be dropped.

triangles : List ( vertex, vertex, vertex ) -> TriangularMesh vertex

Create a mesh from a list of triangular faces, where each face is given as a tuple of three vertices. Note that this will not perform any kind of vertex deduplication, so if any vertices are shared between different triangles then they will occur more than once in the resulting mesh's vertex array.

mesh =
    TriangleMesh.triangles [ ( a, b, c ), ( a, c, d ) ]


TriangleMesh.vertices mesh
--> Array.fromList [ a, b, c, a, c, d ]


Array.faceIndices mesh
--> [ ( 0, 1, 2 ), ( 3, 4, 5 ) ]
fan : vertex -> List vertex -> TriangularMesh vertex

Create a fan-shaped mesh from the first given vertex to all vertices in the given list. If the given list is empty or has only one element, then an empty mesh is returned. Otherwise, the first face will be from the first given vertex to the first and second list vertices, the second face will be from the first given vertex to the second and third list vertices, etc.

mesh =
    TriangleMesh.fan a [ b, c, d, e ]


TriangleMesh.vertices mesh
--> Array.fromList [ a, b, c, d, e ]


TriangleMesh.faceIndices mesh
--> [ ( 0, 1, 2 ), ( 0, 2, 3 ), ( 0, 3, 4 ) ]


TriangleMesh.faceVertices mesh
--> [ ( a, b, c ), ( a, c, d ), ( a, d, e ) ]
strip : List vertex -> List vertex -> TriangularMesh vertex

Create a strip-shaped mesh between two lists of vertices. The two lists should be the same length; if one list is longer, the extra vertices will be dropped. To get triangles with counterclockwise winding order, the second list should be to the left of the first; for example, for two left-to-right vertex lists, the second should be above the first.

mesh =
    TriangleMesh.strip [ a, b, c ] [ d, e, f ]


TriangleMesh.faceVertices mesh
--> [ ( a, b, e )
--> , ( a, e, d )
--> , ( b, c, f )
--> , ( b, f, e )
--> ]
combine : List (TriangularMesh a) -> TriangularMesh a

Combine a list of meshes into a single mesh. This concatenates the vertex arrays of each mesh and adjusts face indices to refer to the combined vertex array.

square =
    TriangularMesh.with
        { vertices = Array.fromList [ a, b, c, d ]
        , faceIndices = [ ( 0, 1, 2 ), ( 0, 2, 3 ) ]
        }


triangle =
    TriangularMesh.with
        { vertices = Array.fromList [ e, f, g ]
        , faceIndices = [ ( 0, 1, 2 ) ]
        }


TriangularMesh.combine [ square, triangle ]
--> TriangularMesh.with
-->     { vertices =
-->         Array.fromList [ a, b, c, d, e, f, g ]
-->     , faceIndices =
-->         [ ( 0, 1, 2 )
-->         , ( 0, 2, 3 )
-->         , ( 4, 5, 6 )
-->         ]
-->     }


TriangularMesh.combine [ triangle, square ]
--> TriangularMesh.with
-->     { vertices =
-->         Array.fromList [ e, f, g, a, b, c, d ]
-->     , faceIndices =
-->         [ ( 0, 1, 2 )
-->         , ( 3, 4, 5 )
-->         , ( 3, 5, 6 )
-->         ]
-->     }

Properties

vertices : TriangularMesh vertex -> Array vertex

Get the vertices of a mesh.

TriangularMesh.vertices square
--> Array.fromList [ a, b, c, d ]
vertex : Int -> TriangularMesh vertex -> Maybe vertex

Get a particular vertex of a mesh by index. If the index is out of range, returns Nothing.

TriangularMesh.vertex 1 square
--> Just b


TriangularMesh.vertex 4 square
--> Nothing
faceIndices : TriangularMesh vertex -> List ( Int, Int, Int )

Get the faces of a mesh as triples of vertex indices.

TriangularMesh.faceIndices square
--> [ ( 0, 1, 2 ), ( 0, 2, 3 ) ]
faceVertices : TriangularMesh vertex -> List ( vertex, vertex, vertex )

Get the faces of a mesh as triples of vertices.

TriangularMesh.faceVertices square
--> [ ( a, b, c ), ( a, c, d ) ]
edgeIndices : TriangularMesh vertex -> List ( Int, Int )

Get all of the edges of a mesh as pairs of vertex indices. Each edge will only be returned once, with the lower-index vertex listed first, and will be returned in sorted order.

TriangularMesh.edgeIndices square
--> [ ( 0, 1 )
--> , ( 0, 2 )
--> , ( 0, 3 )
--> , ( 1, 2 )
--> , ( 2, 3 )
--> ]
edgeVertices : TriangularMesh vertex -> List ( vertex, vertex )

Get all of the edges of a mesh as pairs of vertices. Each edge will only be returned once, with the lower-index vertex listed first, and will be returned in sorted order.

TriangularMesh.edgeVertices square
--> [ ( a, b )
--> , ( a, c )
--> , ( a, d )
--> , ( b, c )
--> , ( c, d )
--> ]

Transformations

mapVertices : (a -> b) -> TriangularMesh a -> TriangularMesh b

Transform a mesh by applying the given function to each of its vertices. For example, if you had a 2D mesh where each vertex was an ( x, y ) tuple and you wanted to convert it to a 3D mesh on the XY plane, you might use

mesh2d : TriangularMesh ( Float, Float )
mesh2d =
    ...


to3d : ( Float, Float ) -> ( Float, Float, Float )
to3d ( x, y ) =
    ( x, y, 0 )


mesh3d : TriangularMesh ( Float, Float, Float )
mesh3d =
    TriangularMesh.mapVertices to3d mesh2d