package OSCADml

  1. Overview
  2. Docs
Legend:
Library
Module
Module type
Parameter
Class
Class type

Path transfomations (default vs euler)

open OCADml
open OSCADml

We'll use a simple elbow shape for our sweeps so that its orientation is easily discernible along the path.

let poly =
  [ -10., -1.; -10., 6.; -7., 6.; -7., 1.; 7., 1.; 7., 6.; 10., 6.; 10., -1. ]
  |> Path2.of_tups
  |> Path2.scale (v2 0.7 0.7)
  |> Poly2.make

Paths radiating outwards from the origin, angled with 45° steps.

let paths =
  let d = 20.
  and p s = V3.[ v (x s) (y s) (z s); v3 (x s *. 2.) (y s *. 2.) (z s *. 2.) ] in
  let out = [ v3 d 0. 0.; v3 d 0. d; v3 d 0. (-.d) ] in
  let f i = List.map (fun s -> V3.rotate (v3 0. 0. Float.(pi /. 4. *. i)) s |> p) out in
  p (v3 0. 0. d) :: p (v3 0. 0. (-.d)) :: List.concat_map f (List.init 8 Float.of_int)

Original orientation of the shape poly for reference.

let flat = Scad.extrude ~height:1. (Scad.of_poly2 poly)

Extrude poly along each of the generated paths, using either default/standard, or euler path transformations (see Path3.to_transforms).

let starburst ~euler =
  let scad =
    let f path = Scad.of_mesh @@ Mesh.path_extrude ~euler ~path poly in
    Scad.union @@ (flat :: List.map f paths)
  and name =
    Printf.sprintf "sweep_starburst_%s.scad" (if euler then "euler" else "default")
  in
  Scad.to_file name scad

Note that with the default (non-euler) path transformations, the orienation of the polygon on the xy plane relative to the starting tangent of te path determines the starting orientation of the sweep. This is in contrast to to when euler is true, where there is radial symmetetry around the z-axis.

let () = starburst ~euler:false (* default path transformations *)

let () = starburst ~euler:true (* euler path transformations *)

A conical path that will reveal to us some of the quirks of the default (non-euler) transformations calculated by Path3.to_transforms.

let path =
  let step = 0.005 in
  let f i =
    let t = Float.of_int i *. step in
    let x = ((t /. 1.5) +. 0.5) *. 100. *. Float.cos (6. *. 360. *. t *. Float.pi /. 180.)
    and y = ((t /. 1.5) +. 0.5) *. 100. *. Float.sin (6. *. 360. *. t *. Float.pi /. 180.)
    and z = 200. *. (1. -. t) in
    v3 x y z
  in
  List.init (Int.of_float (1. /. step)) f

Here, much like in the example in the sweep example of the OpenSCAD list-comprehension-demos library, we can see the accumulated twisting introduced by the default interpretation of the paths tangents.

let () =
  Scad.to_file "sweep_path_default.scad" (Scad.of_mesh @@ Mesh.path_extrude ~path poly)

In some scenarios, you may find the result when euler is true to be more intuitive, as it is here (more closely resembling the special cased Mesh.helix_extrude in this case).

let () =
  Scad.to_file
    "sweep_path_euler.scad"
    (Scad.of_mesh @@ Mesh.path_extrude ~euler:true ~path poly)