package OCADml
Install
Dune Dependency
Authors
Maintainers
Sources
sha256=ee57fc1985cabbb0b55ec56f97bf5f46f02b4b6c27ee4b5b5525d6bc229b9fb1
sha512=ebdc09b5725a2eb1789e789d387023b746a9bfbe02036890361edfd505ba00320f557d4b07a2b249e69317e1cec316599f5663ed8678e491c45562535354553e
doc/OCADml/OCADml/Mesh/index.html
Module OCADml.Mesh
Source
Generation, and manipulation of 3-dimensional meshes (points and faces).
This data type and its constructors/transformers are based on the the vnf structure module of the BOSL2 OpenSCAD library.
Points and faces 3-dimensional mesh.
Basic Constructors
make ~points ~faces
Create a mesh t
from a list of V3.t
points
, and a list of faces
described by indices into points
.
Accessors
Low-level Generators
type endcaps = [
| `Loop
(*Last/top row wrapped to the first/bottom
*)| `Both
(*Both bottom and top rows are closed with flat faces
*)| `None
(*Neither top or bottom rows are closed with a face
*)| `Top
(*A face is generated to close the top row with itself
*)| `Bot
(*A face is generated to close the bottom row with itself
*)
]
Describes desired row wrapping behaviour in of_rows
, which creates a mesh from rows of points.
Quadrilateral face triangulation strategy.
prune_rows ?min_dist rows
Filter rows
such that each row polygon is at least min_dist
(default 0.05
) above the plane of the previous polygon, indicating the dropped indices. This can be useful for avoiding self-intersections in the output of of_rows
. Note that all polygons in rows
must be planar, else Failure
will be raised.
val of_rows :
?rev:bool ->
?endcaps:endcaps ->
?col_wrap:bool ->
?style:style ->
V3.t list list ->
t
of_rows ?rev ?endcaps ?col_wrap ?style rows
Create a t
representing a polyhedron from a list of layers (counter_clockwise loops of 3d points). endcaps
defaults to `Both
, which specifies that faces should be generated to close off the bottom and top layers of the generated shape. If it is instead set to `Loop
, the open faces of the first and last layers will be closed with one another. For more advanced usages, one or both of the endcaps can be left open, so the resulting meshes can be closed off by some other means.
col_wrap
sets whether faces should be generated to loop between the ends of each row.- If
rev
istrue
, faces winding direction will be reversed (default =false
) style
governs how the quadrilaterals formed by the rows and columns of points are divided into triangles:`Default
is an arbitrary systematic subdivision in the same direction`Alt
is the uniform subdivision in the other (alternate direction)`MinEdge
picks the shorter edge to subdivide the quadrilateral, so the division may not be uniform across the shape`Quincunx
adds a vertex in the middle of each quadrilateral and creates four triangles`Convex
and`Concave
choose the locally convex/concave subdivision
- If
rows
is empty, aempty
is returned. ThrowsInvalid_argument
ifrows
contains only one row, or if it is not rectangular (any row differs in length).
of_ragged ?looped ?reverse rows
Create a triangular mesh from a list of rows, where each row can differ in length relative to its neighbours by up to 2. Since the rows can be ragged, no (columnar) wrapping is done, thus they are best described as rows, rather than layers as with of_rows
which produces an enclosed polyhedron. Instead, this function is useful for the generation of triangular patches that can be joined with one another to create a complete polyhedron. Setting looped
to true will generate faces between the last and first rows, so long as their lengths differ by no more than 2. Face winding order is reversed if reverse
is true
. Throws Invalid_argument
if a row length delta of greater than 2 is encountered.
of_path3 ?rev layer
Create a mesh from a single path (a closed loop of V3.t
, should be coplanar though it is not confirmed), returning a t
with a single face including all of the points. Face winding order is reversed if rev
is true
. This can be useful for producing a flat patch mesh to be combined with other meshes to produce a complete shape.
of_poly2 ?rev poly
Create a mesh from a 2d polygon. If poly
does not have any holes, then this is equivalent to of_path2
. If there are holes, polyhole partitioning is performed to determine a set of faces that can close the points.
The earcutting algorithm used to partition the polygon into faces is a port of RonaldoCMP's work found here.
of_poly3 ?rev poly
Create a mesh from a 3d polygon. If poly
does not have any holes, then this is equivalent to of_path3
. If there are holes, polyhole partitioning is performed to determine a set of faces that can close the points.
The earcutting algorithm used to partition the polygon into faces is a port of RonaldoCMP's work found here.
of_polygons polys
Create a polyhedron mesh from a list of polygonal point faces.
hull points
Create a convex hull mesh that encloses points
. If the points are coplanar, a 2-dimensional hull is found, resulting in an unclosed single face mesh (as with of_path3
). Unused points are not discarded.
Skins
Functions for generating meshes which cover over a sequence of closed polygonal Path3.t
profiles. Ported from the skin module of the BOSL2 OpenSCAD library.
Path resampling vertex mapping strategies.
Each of these variants specify that profiles of incommensurate length should simply resampled with Path3.subdivide
with the provided point distribution frequency strategy ([`ByLen | `BySeg]
). In the case of `Direct _
, the profiles are assumed to be "lined up", with the points at their zeroth indices corresponding to eachother. The `Reindex _
strategy will rotate the second profile of a pair via Path3.reindex_polygon
following resampling to minimize the distance between the zeroth indices of the two paths.
type duplicator = [
| `Distance
(*Minimize the length of the edges between associated vertices. Best results when connecting discrete polygon profiles with low point counts.
*)| `FastDistance
(*Like
*)`Distance
, but profiles are assumed to already be lined up, with their zeroth indices corresponding to one another.| `Tangent
(*Split finely sampled (convex) curve into groups of points, and map each group to point on the smaller discrete polygon. Can fail if the larger curved path is non-convex, or does not have enough points.
*)
]
Point duplicating vertex mapping strategies.
Each of these variants specify profiles of incommensurate length should be matched up by computing vertex mappings between the profiles, and duplicating vertices on the smaller/shorter profile until the point counts are equalized. See the conspicuously named vertex matching functions Path3.distance_match
, Path3.aligned_distance_match
, and Path3.tangent_match
for more details (also available in the Path2
module).
Vertex count matching strategy specification type.
val slice_profiles :
?looped:bool ->
slices:[< `Flat of int | `Mix of int list ] ->
Path3.t list ->
Path3.t list
slice_profiles ?looped ~slices profiles
Linearly transition between each neighbouring pair of closed paths in profiles
to produce new interpolated list of profiles. The number of slices
inserted between can either be the same between each pair (`Flat n
), or specified separately with `Mix ns
. If looped
is true
, then slices will also be inserted between the last and initial profiles (default is false
). Lists of profiles such as these can be used to produce meshes with of_rows
(as skin
does).
Raises Invalid_argument
if the length of `Mix ns
does not correspond to the number of transitions, or if profiles
has fewer than two elements.
val skin :
?style:style ->
?endcaps:endcaps ->
?refine:int ->
?mapping:[ `Flat of mapping | `Mix of mapping list ] ->
slices:[< `Flat of int | `Mix of int list ] ->
Path3.t list ->
t
skin ?style ?endcaps ?refine ?mapping ~slices profiles
Produce a mesh that skins over two or more 3d profiles
-- closed, ideally coplanar (though some slight variation can be ok) paths. This works by linearly interpolating between neighbouring profiles with slices
steps, and passing the profiles along to of_rows
, which generates faces to enclose the shape. For this to be well defined, each row must have the same length, thus mapping
can be used to specify the strategy used to map/associate the vertices between them and reconcile the point counts and improve alignment for their connecting edges (see resampler
and duplicator
configuration variants). By default this is `Direct
, which simply applies resampling without altering the vertex associations established by the start indices of each profile.
refine
can be specified to apply additional upsampling which may help to improve the smoothness of the resulting mesh. UsesPath3.subdivide
with the sampling frequency indicated forresampler
mapped transitions, and`BySeg
forduplicator
s.slices
andmapping
can be provided as`Flat _
to be applied to all transitions, or as`Mix l
, wherel
is a list with length equal to the number of profile transitions (length profiles - 1
, orlength profiles
ifendcaps
is`Loop
)- NOTE: mixing mapping strategies can be fickle, and some combinations may not work depending on the profiles. This may improve as kinks are worked out, but maybe not
val skin_between :
?style:style ->
?endcaps:[ `Both | `None | `Top | `Bot ] ->
?refine:int ->
?mapping:mapping ->
slices:int ->
Path3.t ->
Path3.t ->
t
skin_between ?style ?endcaps ?refine ?mapping ~slices a b
Create a mesh that skins over a linear interpolation/morph between 3d profiles a
and b
over slices
steps. See skin
for more details.
Sweeps, extrusions, and morphs with roundovers
Sweeps, extrusions and morphs from 2d to 3d. Each of which can be given rounded over end caps via their optional ?caps
parameters with specifications contsructed by the Cap
module. and the optional ?caps
. Roundovers are based on the implementations found in the BOSL2 library's offset_sweep
functions from the rounding module.
Configuration module for declaring how extrusions from 2d to 3d via sweep
should be capped off.
Fixed polygon sweeps and extrusions
val sweep :
?style:style ->
?check_valid:[ `Quality of int | `No ] ->
?merge:bool ->
?winding:[ `CCW | `CW | `NoCheck ] ->
?caps:Cap.t ->
transforms:Affine3.t list ->
Poly2.t ->
t
sweep ?check_valid ?style ?winding ?merge ?fn ?fs ?fa ?caps ~transforms poly
Sweep a 2d polygon into a 3d mesh by applying a sequence of transforms
to the original shape. The winding
parameter can be used to set automatic enforcement of polygon winding direction, which will impact the winding of the generated faces of the mesh. What is done with the endcaps can be specified with caps
. By default the ends of the extrusion are sealed with flat faces, but they can instead be looped to eachother, left empty, or rounded over. If style
is provided, it will be passed along to of_rows
, which handles converting the swept shapes into a mesh.
If merge
is true
(as is default), merge_points
is applied to the resulting mesh, as duplicate points are introduced when end caps are joined to the outer and inner meshes. If the duplicate points aren't a problem for you (they aren't necessarily), this can be turned off to save some compute.
check_valid
determines whether validity checks are performed during offset operations (see Path2.offset
), for cap roundovers (if specified). Additionally, unless check_valid
is `No
, polygon validation will be performed with final outer and inner paths of the caps before their mesh is generated.
val extrude :
?style:style ->
?check_valid:[ `Quality of int | `No ] ->
?merge:bool ->
?winding:[ `CCW | `CW | `NoCheck ] ->
?fa:float ->
?slices:int ->
?scale_ez:(V2.t * V2.t) ->
?twist_ez:(V2.t * V2.t) ->
?scale:V2.t ->
?twist:float ->
?center:bool ->
?caps:[ `Caps of Cap.caps ] ->
height:float ->
Poly2.t ->
t
extrude ~height poly
Vertically extrude a 2d polygon 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. Roundovers described by caps
are taken into account such that the final shape conforms to the specified height
. If height
is less than the combined height of caps
, there will simply be no "mid-section" (and the resulting height will not reflect the height
parameter).
?twist
rotates the shape by the specified angle 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 my improve results.?scale
expands or contracts the shape in X and Y as it is extruded upward. Default is(v2 1. 1.)
, no scaling.- Scaling/twisting proceed linearly by default, though bezier easing can be specified by providing handle points to the
scale_ez
andtwist_ez
parameter respectively. (seePath3.scaler
andPath3.twister
).
val revolve :
?style:style ->
?check_valid:[ `No | `Quality of int ] ->
?merge:bool ->
?winding:[ `CCW | `CW | `NoCheck ] ->
?fn:int ->
?fa:float ->
?fs:float ->
?skew:V2.t ->
?angle:float ->
Poly2.t ->
t
revolve ?angle ?skew poly
Revolve a 2d polygon (defined within the X+ half-plane) around the z-axis. An angle
between 0 and 2π can be provided to specify an incomplete revolution, by default the result loops back onto itself.
skew:{x; y}
skews the revolved mesh in thex
z andy
z planes
val path_extrude :
?style:style ->
?check_valid:[ `Quality of int | `No ] ->
?merge:bool ->
?winding:[ `CCW | `CW | `NoCheck ] ->
?caps:Cap.t ->
?euler:bool ->
?scale_ez:(V2.t * V2.t) ->
?twist_ez:(V2.t * V2.t) ->
?scale:V2.t ->
?twist:float ->
path:Path3.t ->
Poly2.t ->
t
path_extrude ?check_valid ?style ?merge ?winding ?caps ?euler ?scale_ez ?twist_ez ?scale ?twist ~path poly
Extrude a 2d polygon along the given path
into a 3d mesh. This is a convenience function that composes transform generation using Path3.to_transforms
with sweep
.
val helix_extrude :
?style:style ->
?check_valid:[ `Quality of int | `No ] ->
?merge:bool ->
?fn:int ->
?fa:float ->
?fs:float ->
?scale_ez:(V2.t * V2.t) ->
?twist_ez:(V2.t * V2.t) ->
?scale:V2.t ->
?twist:float ->
?caps:[ `Caps of Cap.caps ] ->
?left:bool ->
n_turns:int ->
pitch:float ->
?r2:float ->
float ->
Poly2.t ->
t
helix_extrude ?check_valid ?style ?merge ?fn ?fs ?fa ?scale_ez ?twist_ez ?scale ?twist ?caps ?left ~n_turns ~pitch ?r2 r1 poly
Helical extrusion of a 2d polygon into a 3d mesh. This is a special case of path_extrude
, but following a path generated with Path3.helix
, and using transforms that take the helical rotation into account.
Morphing sweeps and extrusions
These functions serve as the morphing counterparts of the fixed polygon sweeping functions above. In contrast to the more general skin
which transitions between 3d Path3.t
profiles in sequence, these restrict the bounding shapes to 2d, and lift to 3d via the provided transforms, or path specifications. This separation of the morphing transition and spatial transformations allows for the easy addition of non-linear Easing
between the shapes via the ?ez
parameters (default is linear transition along the spatial distance covered by the sweep beginning from its origin).
val morphing_sweep :
?style:style ->
?check_valid:[ `Quality of int | `No ] ->
?merge:bool ->
?winding:[ `CCW | `CW | `NoCheck ] ->
?caps:[ `Caps of Cap.caps ] ->
?outer_map:mapping ->
?hole_map:[ `Same | `Flat of mapping | `Mix of mapping list ] ->
?refine:int ->
?ez:(V2.t * V2.t) ->
transforms:Affine3.t list ->
Poly2.t ->
Poly2.t ->
t
morphing_sweep ~transforms a b
Morph between the polygons a
and b
while sweeping the hybrids along transforms
to create a mesh. The outer_map
, hole_map
, and refine
correspond to the the similarly named parameters of the more general skin
, while the optional ez
parameter allows the transition to be bezier eased via Easing.make
, rather than strictly linearly. See sweep
for details on the remaining common parameters.
val morph :
?style:style ->
?check_valid:[ `Quality of int | `No ] ->
?merge:bool ->
?winding:[ `CCW | `CW | `NoCheck ] ->
?fa:float ->
?slices:int ->
?scale_ez:(V2.t * V2.t) ->
?twist_ez:(V2.t * V2.t) ->
?scale:V2.t ->
?twist:float ->
?center:bool ->
?caps:[ `Caps of Cap.caps ] ->
?outer_map:mapping ->
?hole_map:[ `Flat of mapping | `Mix of mapping list | `Same ] ->
?refine:int ->
?ez:(V2.t * V2.t) ->
height:float ->
Poly2.t ->
Poly2.t ->
t
morph ~height a b
Vertically morph between the 2d polygons a
and b
. This function is to morphing_sweep
, as extrude
is to sweep
. See each of the former for details on their common parameters.
val path_morph :
?style:style ->
?check_valid:[ `Quality of int | `No ] ->
?merge:bool ->
?winding:[ `CCW | `CW | `NoCheck ] ->
?caps:[ `Caps of Cap.caps ] ->
?outer_map:mapping ->
?hole_map:[ `Flat of mapping | `Mix of mapping list | `Same ] ->
?refine:int ->
?ez:(V2.t * V2.t) ->
?euler:bool ->
?scale_ez:(V2.t * V2.t) ->
?twist_ez:(V2.t * V2.t) ->
?scale:V2.t ->
?twist:float ->
path:Path3.t ->
Poly2.t ->
Poly2.t ->
t
path_morph ~path poly
Morph between the 2d polygons a
and b
along the given path
. This is a convenience function that composes transform generation using Path3.to_transforms
with morphing_sweep
.
val helix_morph :
?style:style ->
?check_valid:[ `Quality of int | `No ] ->
?merge:bool ->
?fn:int ->
?fa:float ->
?fs:float ->
?scale_ez:(V2.t * V2.t) ->
?twist_ez:(V2.t * V2.t) ->
?scale:V2.t ->
?twist:float ->
?caps:[ `Caps of Cap.caps ] ->
?outer_map:mapping ->
?hole_map:[ `Flat of mapping | `Mix of mapping list | `Same ] ->
?refine:int ->
?ez:(V2.t * V2.t) ->
?left:bool ->
n_turns:int ->
pitch:float ->
?r2:float ->
float ->
Poly2.t ->
Poly2.t ->
t
helix_morph ~n_turns ~pitch ?r2 r1 a b
Morph between the 2d polygons a
and b
along a helical path. This is a special case of path_morph
, but following a path generated with Path3.helix
, and using transforms that take the helical rotation into account.
Generalized prisms with continous rounding
val prism :
?debug:bool ->
?fn:int ->
?holes:Prism.holes ->
?outer:Prism.spec ->
Poly3.t ->
Poly3.t ->
t
prism ?debug ?fn ?holes ?outer bottom top
Create a prism with continuous curvature rounding from the given bottom
and top
polygons. The edges running between the corresponding paths must produce a valid polyhedron with coplanar side faces, thus the top should generally be the same shape as the bottom translated/transformed in such a way as to not violate this assumption (avoid z-rotation for one). Roundover specifications are provided with outer
and holes
(see Prism.spec
and Prism.holes
for details).
debug
can be set totrue
to skip validity checks that would otherwise raise exceptions on failure, so a mesh can still be obtained for inspection.
val linear_prism :
?debug:bool ->
?fn:int ->
?holes:Prism.holes ->
?outer:Prism.spec ->
?center:bool ->
height:float ->
Poly2.t ->
t
linear_prism ?debug ?fn ?holes ?outer ?center ~height bottom
Create a prism with continuous curvature rounding by extruding the polygon bottom
linearaly upward to the given height
. If center
is true
, the resulting prism will be centred in z around the xy plane. See the more general case prism
for more details.
Function Plotting
Ported from the PlotFunction library by Ryan Colyer.
val cartesian_plot :
min_x:float ->
x_steps:int ->
max_x:float ->
min_y:float ->
y_steps:int ->
max_y:float ->
(x:float -> y:float -> float) ->
t
cartesian_plot ~min_x ~x_steps ~max_x ~min_y ~y_steps ~max_y f
Create a mesh of the function f
(from x and y to z) over the ranges of x and y defined by the rest of the parameters.
polar_plot ?r_step ~max_r f
Create a mesh of the function f
(from radius and angle to z) between the z-axis and the radius max_r
, with the minimum radial step r_step
.
val axial_plot :
?fn:int ->
min_z:float ->
z_steps:int ->
max_z:float ->
(z:float -> a:float -> float) ->
t
axial_plot ?fn ~min_z ~z_step ~max_z f
Create a mesh of the function f
(from z-height and angle to radius). fn
sets the number of angular steps around the z-axis.
Mesh Utilities
join ts
Join a list of meshes. This is not a boolean operation, it is simply collecting the points from each and updating face indices accordingly. Intended for use when building a closed mesh from a set of partial meshes.
merge_points ?eps t
Eliminate duplicate points (less than eps
distance apart) from t
.
drop_unused_points t
Drop unreferenced points (not included in any face) from the mesh t
.
triangulate ?eps t
Triangulate the faces of the mesh t
. Some degree of coplanarity in the input faces can be fine, though too much can cause triangulation to fail. If provided, eps
is used for duplicate point and collinearity checks.
Basic Transfomations
Output
to_stl ?ascii ?rev ?eps path t
Write the mesh t
to disk at path
as an stl. Binary serialization is performed by default, but the ascii
format is also available.
eps
can be provided to control the precision of point deduplication and face triangulation operations required befor export (default is1e-6
)- As OCADml meshes (
t
) are typically generated to follow the CCW inner face convention of OpenSCAD, this can result in normals pointing the opposite direction expected by other programs with which you may want to use the outputstl
. Thus facets are reversed by default during serialization, however this can be avoided by setting~rev:false
.