Module OManifold.Manifold

Manifold triangular meshes representing 3d solid objects

module Id : sig ... end
type size = {
  1. surface_area : float;
  2. volume : float;
}

Spatial properties of a Manifold.t, returned by size

module Curvature : sig ... end
type t

Basic Constructors

val empty : unit -> t

empty ()

Construct an empty manifold.

val copy : t -> t

copy t

Return a copy of the manifold t.

val as_original : t -> t

as_original t

If you copy a manifold, but you want this new copy to have new properties (e.g. a different UV mapping), you can reset its relational ids (as found in MMeshGL.t to new originals, meaning it will now be referenced by its descendents instead of the meshes it was built from, allowing you to differentiate the copies when applying your properties to the final result.

This function also condenses all coplanar faces in the relation, and collapses those edges. If you want to have inconsistent properties across these faces, meaning you want to preserve some of these edges, you should instead use to_mmeshgl, calculate your properties and use these to construct a new manifold.

Topology

val compose : t list -> t

compose ts Constructs a new manifold from a list of other manifolds. This is a purely topological operation, so care should be taken to avoid creating overlapping results. It is the inverse operation of decompose.

val decompose : t -> t list

decompose t

This operation returns a list of manifolds that are topologically disconnected. If everything is connected, the result is singular copy of the original. It is the inverse operation of compose.

Shapes

val tetrahedron : unit -> t

tetrahedron ()

Create a tetrahedron centred at the origin with one vertex at (v3 1. 1. 1.) and the rest at similarly symmetric points.

val sphere : ?fn:int -> float -> t

sphere ?fn radius

Create a sphere with given radius at the origin of the coordinate system. The number of segments along the diameter can be explicitly set by fn, otherwise it is determined by the quality globals.

val cube : ?center:bool -> OCADml.v3 -> t

cube ?center dimensions

Create a cube in the first octant, with the given xyz dimensions. When center is true, the cube is centered on the origin.

val cylinder : ?center:bool -> ?fn:int -> height:float -> float -> t

cylinder ?center ?fn ~height radius

Creates a cylinder centered about the z-axis. When center is true, it will also be centered vertically, otherwise the base will sit upon the XY plane. The number of segments along the diameter can be explicitly set by fn, otherwise it is determined by the quality globals.

val cone : ?center:bool -> ?fn:int -> height:float -> float -> float -> t

cone ?center ?fn ~height r1 r2

Create cone with bottom radius r1 and top radius r2. When center is true, it will also be centered vertically, otherwise the base will sit upon the XY plane. The number of segments along the diameter can be explicitly set by fn, otherwise it is determined by the quality globals.

Mesh Conversions

val of_mmeshgl : {mmeshgl}2 -> (t, string) Stdlib.result

of_mmeshgl m

Create a manifold from the mesh m, returning Error if m is not an oriented 2-manifold. Will collapse degenerate triangles and unnecessary vertices.

val of_mmeshgl_exn : {mmeshgl}2 -> t

of_mmeshgl_exn ?properties m

Same as of_mmeshgl, but raising a Failure rather than returning an Error.

val of_mesh : ?rev:bool -> OCADml.Mesh.t -> (t, string) Stdlib.result

of_mesh ?rev m

Create a manifold from an OCADml mesh m, returning Error if m is not an oriented 2-manifold. Will collapse degenerate triangles and unnecessary vertices. If rev is true (as it is by default), faces of the input mesh are reversed (as the winding convention in OCADml is opposite to Manifold)

val of_mesh_exn : ?rev:bool -> OCADml.Mesh.t -> t

of_mesh_exn ?rev m

Same as of_mesh, but raising a Failure rather than returning an Error.

val smooth : ?smoothness:(int * float) list -> MMeshGL.t -> (t, string) Stdlib.result

smooth ?smoothness m

Constructs a smooth version of the input mesh m by creating tangents, returning an error if you have already supplied tangents for it. The actual triangle resolution is unchanged, thus you will likely want to follow up with refine to interpolate to higher-resolution curves.

By default, every edge is calculated for maximum smoothness (very much approximately), attempting to minimize the maximum mean Curvature magnitude. No higher-order derivatives are considered, as the interpolation is independent per triangle, only sharing constraints on their boundaries. To control the relative smoothness at particular halfedges (ideally limited to a small subset of all halfedges), smoothness can be provided with (index, s) pairs specifying a smoothness factor s between 0. and 1. for the index interperpreted as 3 * triangle + {0,1,2} where 0 is the edge between the first and second vertices of the triangle.

At a smoothness value of zero, a sharp crease is made. The smoothness is interpolated along each edge, so the specified value should be thought of as an average. Where exactly two sharpened edges meet at a vertex, their tangents are rotated to be colinear so that the sharpened edge can be continuous. Vertices with only one sharpened edge are completely smooth, allowing sharpened edges to smoothly vanish at termination. A single vertex can be sharpened by sharping all edges that are incident on it, allowing cones to be formed.

val smooth_exn : ?smoothness:(int * float) list -> MMeshGL.t -> t

smooth_exn ?smoothness m

Same as smooth, but raising Failure rather than returning Error.

val to_mmeshgl : t -> {mmeshgl}2

to_mmeshgl t

Obtain a graphics library (gl) friendly mesh representation of the manifold t.

val to_mesh : t -> OCADml.Mesh.t

to_mesh t

Obtain an OCADml mesh describing the shape ot the manifold t.

2D to 3D

val extrude : ?slices:int -> ?fa:float -> ?twist:float -> ?scale:OCADml.v2 -> ?center:bool -> height:float -> Cross.t -> t

extrude ?slices ?twist ?scale ~height cross_section

Vertically extrude a 2d cross_section from the XY plane to height. If ?center is true, the resulting 3D object is centered around the XY plane, rather than resting on top of it.

  • ?twist rotates the shape by the specified angle (in radians) as it is extruded upwards
  • ?slices specifies the number of intermediate points along the Z axis of the extrusion. By default this increases with the value of ?twist, though manual refinement may improve results.
  • ?scale expands or contracts the shape in X and Y as it is extruded upward. Default is (v2 1. 1.), no scaling. If set to (v2 0. 0.), a pure cone is formed, with only a single vertex at the top.
val revolve : ?fn:int -> Cross.t -> t

revolve ?fn cross_section

Revolve a 2d cross_section around the y-axis and then set this as the z-axis of the resulting manifold. If the polygons cross the y-axis, only the part on the positive x side is used. Geometrically valid input will result in geometrically valid output. The number of segments in the revolution can be set explicitly with fn, otherwise it is determined by the quality globals.

Booleans

val boolean : op:[ `Add | `Subtract | `Intersect ] -> t -> t -> t
val batch_boolean : op:[ `Add | `Subtract | `Intersect ] -> t list -> t
val add : t -> t -> t

add a b

Union (logical or) the manifolds a and b.

val union : t list -> t

union ts

Union (logical or) the list of manifolds ts.

val sub : t -> t -> t

sub a b

Subtract (logical and not) the manifold b from the manifold a.

val difference : t -> t list -> t

difference t d

Subtract (logical and not) the list of manifolds d from the manifold t.

val intersect : t -> t -> t

intersect a b

Compute the intersection (logical and) of the manifolds a and b.

val intersection : t list -> t

intersection ts

Compute the intersection (logical and) of the manifolds ts. Only the area which is common or shared by all shapes are retained. If ts is empty, an empty manifold t will result.

val split : t -> t -> t * t

split a b

Splits the manifold a into two using the cutter manifold b. The first result is the intersection, and the second is the difference.

val split_by_plane : OCADml.Plane.t -> t -> t * t

split_by_plane p t

Splits the manifold t in two, one above the plane p, and the other below.

val trim_by_plane : OCADml.Plane.t -> t -> t

trim_by_plane p t

Cut away the portion of the manifold t lying below the plane p.

Transformations

val translate : OCADml.v3 -> t -> t

translate p t

Move t along the vector p.

val xtrans : float -> t -> t

xtrans x t

Move t by the distance x along the x-axis.

val ytrans : float -> t -> t

ytrans y t

Move t by the distance y along the y-axis.

val ztrans : float -> t -> t

ztrans z t

Move t by the distance z along the z-axis.

val rotate : ?about:OCADml.v3 -> OCADml.v3 -> t -> t

rotate ?about r t

Performs an Euler rotation (zyx). If it is provided, rotations are performed around the point about, otherwise rotation is about the origin. Angle(s) r are in radians.

val xrot : ?about:OCADml.v3 -> float -> t -> t

xrot ?about r t

Rotate the manifold t around the x-axis through the origin (or the point about if provided) by r (in radians).

val yrot : ?about:OCADml.v3 -> float -> t -> t

yrot ?about r t

Rotate the manifold t around the y-axis through the origin (or the point about if provided) by r (in radians).

val zrot : ?about:OCADml.v3 -> float -> t -> t

zrot ?about r t

Rotate the manifold t around the z-axis through the origin (or the point about if provided) by r (in radians).

val mirror : OCADml.v3 -> t -> t

mirror n t

Mirror the manifold t over the plane described by the unit form of the normal vector n. If the length of n is zero, an empty manifold is returned.

val affine : OCADml.Affine3.t -> t -> t

affine m t

Transform the manifold t with the affine transformation matrix m.

val quaternion : ?about:OCADml.v3 -> OCADml.Quaternion.t -> t -> t

quaternion ?about q t

Applys the quaternion rotation q around the origin (or the point about if provided) to t.

val axis_rotate : ?about:OCADml.v3 -> OCADml.v3 -> float -> t -> t

axis_rotate ?about ax r t

Rotates t about the arbitrary axis ax through the origin (or the point about if provided) by the angle r (in radians).

val warp : (OCADml.v3 -> OCADml.v3) -> t -> t

warp f t

Map over the vertices of the manifold t with the function f, allowing their positions to be updated arbitrarily, but note that the topology is unchanged. It is easy to create a function that warps a geometrically valid object into one which overlaps, but that is not checked here, so it is up to the user to choose their function with discretion.

val scale : OCADml.v3 -> t -> t

scale factors t

Scales t by the given factors in xyz.

val xscale : float -> t -> t

xscale s t

Scales t by the factor s in the x-dimension.

val yscale : float -> t -> t

yscale s t

Scales t by the factor s in the y-dimension.

val zscale : float -> t -> t

zscale s t

Scales t by the factor s in the z-dimension.

val refine : int -> t -> t

refine n t

Increase the density of the meshes in t by splitting every edge into n pieces. For instance, with n = 2, each triangle will be split into 4 triangles. These will all be coplanar (and will not be immediately collapsed) unless the contained MMeshGL.t within has MMeshGL.halfedge_tangents specified (e.g. from the smooth constructor), in which case the new vertices will be moved to the interpolated surface according to their barycentric coordinates.

val hull : t list -> (t, string) Stdlib.result

hull ts

Create a convex hull that encloses all of the vertices of the manifolds in ts. Note that this operation comes from OCADml and is not guaranteed to produce a valid manifold.

val hull_exn : t list -> t

hull_exn ts

Same as hull, but a Failure is raised if the resulting mesh does not describe a valid manifold.

Data Extraction

val original_id : t -> Id.t

original_id t

If this mesh is an original, this returns it unique id that can be referenced by product manifolds (for the purposes of reappling mesh properties).

val num_vert : t -> int

num_vert t

The number of vertices in the manifold t.

val num_edge : t -> int

num_edge t

The number of edges in the manifold t.

val num_tri : t -> int

num_tri t

The number of triangles in the manifold t.

val bounding_box : t -> OCADml.Box3.t

bounding_box t

Return the axis-aligned bounding box of all of the manifold t's vertices.

val precision : t -> float

precision t

Returns the precision of this manifold's vertices, which tracks the approximate rounding error over all the transforms and operations that have led to this state. Any triangles that are colinear within this precision are considered degenerate and removed. This is the value of ε defining ε-valid.

val genus : t -> int

genus t

The genus is a topological property of the manifold, representing the number of "handles". A sphere is 0, torus 1, etc. It is only meaningful for a single mesh, so it is best use decompose first.

val size : t -> size

size t

The physical size (surface area and volume) of the manifold t.

val curvature : t -> Curvature.t

curvature t

The inverse of the radius of curvature, and signed such that positive is convex and negative is concave. There are two orthogonal principal curvatures at any point on a manifold, with one maximum and the other minimum. Gaussian curvature is their product, while mean curvature is their sum. This approximates them for every vertex (returned as vectors in the structure) and also returns their minimum and maximum values.

val points : t -> OCADml.v3 list

points t

Retrieve the points making up the meshes of the manifold t.