Skip to content

Commit

Permalink
Add bezier skline example + other example touchups
Browse files Browse the repository at this point in the history
Bumps OCADml dep to v0.6.0 in order to add a skline example. Now that
OCADml has direct stl export though, I need to consider moving the
examples under that library. Or, just replicate what currently exists
for now, and don't add further examples here (which are really OCADml
mesh generations without CSG) while I consider if this manual should be
trimmed down to something more OpenSCAD centric.
  • Loading branch information
geoffder committed May 2, 2023
1 parent 7886391 commit a0a7ef5
Show file tree
Hide file tree
Showing 45 changed files with 206 additions and 47 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -4,3 +4,4 @@ _opam/
_esy/

examples/scads
examples/pngs/incl_*.png
4 changes: 2 additions & 2 deletions OSCADml.opam
Expand Up @@ -9,7 +9,7 @@ authors: [
"Masaki Nakano<namachan10777@gmail.com>"
]
license: "GPL-2.0-or-later"
tags: ["OCADml" "CAD" "OpenSCAD"]
tags: ["OCADml" "CAD" "OpenSCAD" "CSG"]
homepage: "https://github.com/OCADml/OSCADml"
doc: "https://ocadml.github.io/OSCADml"
bug-reports: "https://github.com/OCADml/OSCADml/issues"
Expand All @@ -18,7 +18,7 @@ depends: [
"ocaml" {>= "4.14.0"}
"gg" {>= "1.0.0"}
"cairo2" {>= "0.6.2"}
"OCADml" {>= "0.5.0"}
"OCADml" {>= "0.6.0"}
"odoc" {with-doc}
]
build: [
Expand Down
1 change: 1 addition & 0 deletions docs/index.mld
Expand Up @@ -85,6 +85,7 @@ should serve as a helpful reference.

{2 Skins and Morphs}
- {{!page-"profile_skinning"} {b Profile skinning}}
- {{!page-"spline_skinning"} {b Continuous skinning with Bézier splines}}
- {{!page-"morphing_sweeps"} {b Morphing sweeps and extrusions}}

{2 Function Plotting}
Expand Down
4 changes: 2 additions & 2 deletions dune-project
Expand Up @@ -27,7 +27,7 @@
(description
"OSCADml is an OCaml front-end to the OpenSCAD CAD programming language.")
(tags
("OCADml" "CAD" "OpenSCAD"))
("OCADml" "CAD" "OpenSCAD" "CSG"))
(depends
(ocaml
(>= 4.14.0))
Expand All @@ -36,4 +36,4 @@
(cairo2
(>= 0.6.2))
(OCADml
(>= 0.5.0))))
(>= 0.6.0))))
4 changes: 1 addition & 3 deletions examples/arc_points.ml
Expand Up @@ -33,9 +33,7 @@ let () =
in
let wedge = Scad.extrude ~height:1. @@ Scad.of_path2 arc
and marks =
Debug.show_path2 show arc
|> Scad.translate (v3 0. 0. 1.1)
|> Scad.color ~alpha:0.8 Color.Magenta
Scad.color ~alpha:0.8 Color.Magenta @@ Scad.ztrans 1.1 (Debug.show_path2 show arc)
in
Scad.to_file "arc_wedge_2d.scad" @@ Scad.union [ wedge; marks ]

Expand Down
4 changes: 1 addition & 3 deletions examples/docs/arc_points.mld
Expand Up @@ -42,9 +42,7 @@ let () =
in
let wedge = Scad.extrude ~height:1. @@ Scad.of_path2 arc
and marks =
Debug.show_path2 show arc
|> Scad.translate (v3 0. 0. 1.1)
|> Scad.color ~alpha:0.8 Color.Magenta
Scad.color ~alpha:0.8 Color.Magenta @@ Scad.ztrans 1.1 (Debug.show_path2 show arc)
in
Scad.to_file "arc_wedge_2d.scad" @@ Scad.union [ wedge; marks ]
]}
Expand Down
2 changes: 1 addition & 1 deletion examples/docs/morphing_sweeps.mld
Expand Up @@ -18,7 +18,7 @@ let () =
V3.[ v 0. 0. 2.; v 0. 20. 20.; v 40. 20. 10.; v 30. 0. 10. ]
|> Path3.quaternion (Quaternion.make (v3 1. 1. 0.) (Float.pi /. -5.))
in
Bezier3.curve ~fn:60 @@ Bezier3.of_path ~size:(`Flat (`Rel 0.3)) control
Bezier3.curve ~fn:80 @@ Bezier3.of_path ~size:(`Flat (`Rel 0.3)) control
and caps =
Mesh.Cap.(capped ~bot:(round @@ circ (`Radius 0.5)) ~top:(round @@ circ (`Radius 0.5)))
and a = Poly2.ring ~fn:5 ~thickness:(v2 2.5 2.5) (v2 6. 6.)
Expand Down
2 changes: 1 addition & 1 deletion examples/docs/polyholes.mld
Expand Up @@ -23,7 +23,7 @@ let () =
|> Scad.translate (v3 0. 0. (-3.))
|> Scad.color ~alpha:0.5 Color.BlueViolet
in
Scad.union [ poly; reference ]
Scad.add poly reference
in
Scad.to_file "polyholes.scad" scad
]}
Expand Down
19 changes: 3 additions & 16 deletions examples/docs/profile_skinning.mld
Expand Up @@ -15,14 +15,13 @@ connector.

{[
let profiles =
let fn = 32
and up h = Path3.translate (v3 0. 0. h) in
let fn = 32 in
let base =
let sq = Path3.square ~center:true (v2 2. 4.) in
Path3.(roundover ~fn (Round.flat ~corner:(Round.circ (`Radius 0.5)) sq))
and c r h = up h @@ Path3.circle ~fn r in
and c r h = Path3.ztrans h @@ Path3.circle ~fn r in
let cones = List.map (fun h -> [ c 0.6 h; c 0.5 (h +. 1.) ]) [ 4.; 5.; 6. ] in
List.flatten @@ ([ base; up 2. base; c 0.5 3.; c 0.5 4. ] :: cones)
List.flatten ([ base; Path3.ztrans 2. base; c 0.5 3.; c 0.5 4. ] :: cones)
]}

A quick look at the points of our profiles we are about to mesh over with
Expand Down Expand Up @@ -56,15 +55,3 @@ let () =
<img src="_assets/vaccum_connector.png" style="width:150mm;"/>
</p> %}


{[
let () =
Mesh.skin
~refine:2
~slices:(`Flat 25)
~mapping:(`Flat `Tangent)
Path3.[ circle ~fn:5 4.; translate (v3 0. 0. 3.) @@ circle ~fn:80 2. ]
|> Scad.of_mesh
|> Scad.to_file "tangent_skin_test.scad"
]}

4 changes: 2 additions & 2 deletions examples/docs/spline.mld
Expand Up @@ -10,7 +10,7 @@ Control points that our
through.

{[
let control = [ v2 0. 10.; v2 10. 40.; v2 20. 40.; v2 30. (-20.); v2 40. (-40.) ]
let control = V2.[ v 0. 10.; v 10. 40.; v 20. 40.; v 30. (-20.); v 40. (-40.) ]
]}

Mark our [control] points with the debugging helper
Expand Down Expand Up @@ -38,7 +38,7 @@ let line =
Union our control point [marks] and [line] sweep shapes and output to file.

{[
let () = Scad.to_file "spline.scad" (Scad.union [ line; marks ])
let () = Scad.to_file "spline.scad" (Scad.add line marks)
]}

{%html:
Expand Down
96 changes: 96 additions & 0 deletions examples/docs/spline_skinning.mld
@@ -0,0 +1,96 @@
{0 Bézier Sklines}

{[
open OCADml
open OSCADml
]}

{{!OCADml.Mesh.skline} [Mesh.skline]}, like {{!OCADml.Mesh.skin}
[Mesh.skin]} provides a means of generating a mesh that covers a series of
given profiles, but where [skin] linearly transistions between each profile
independently, [skline] splines through each of the paths formed by the
associated vertices from the first profile to the last (or in a loop).
to generate meshes that cover over series of profiles. However, unlike
[skin] only resampling is made available for mapping vertices between
incomensurate profiles as the point duplication methods (tangent and
distance) can easily lead to edge intersections.

{[
let handle_profiles =
let circ = Path3.circle ~fn:64 5. in
let base = Path3.scale (v3 1.2 1.2 1.) circ
and handle = Path3.scale (v3 0.7 0.7 1.) circ in
Path3.
[ ztrans (-3.) base
; circ
; translate (v3 15. 0. 20.) (yrot (Float.pi /. 2.) handle)
; xtrans 30. (yrot Float.pi circ)
; translate (v3 30. 0. (-3.)) (yrot Float.pi base)
]
]}

A quick look at the points of our profiles we are about to spline over with
alternating colours may help a bit to conceptualize what we are about to
give {{!OCADml.Mesh.skline} [Mesh.skline]} to work with.

{[
let () =
let show i =
let c = if i mod 2 = 0 then Color.Magenta else Color.Aquamarine in
Debug.show_path3 (fun _ -> Scad.(color c @@ sphere 0.2))
in
List.mapi show handle_profiles |> Scad.union |> Scad.to_file "handle_points.scad"
]}

{%html:
<p style="text-align:center;">
<img src="_assets/handle_points.png" style="width:150mm;"/>
</p> %}

Using the [?tangents] parameter of {{!OCADml.Bezier3.of_path}
[Bezier3.of_path]} we can specify the tangents we want for each profile,
rather than leaving them up to the automatically computed derivatives (that
may differ for each edge path tracing between the profiles). Here we
contstrain them to cardinals so we can get a handle that sticks closer to
right angles.

{[
let () =
let up = v3 0. 0. 1. in
let tangents = `Tangents [ up; up; v3 1. 0. 0.; V3.neg up; V3.neg up ] in
Mesh.skline ~fn:200 ~size:(`Flat (`Rel 0.5)) ~tangents handle_profiles
|> Scad.of_mesh
|> Scad.to_file ~incl:true "handle_skline.scad"
]}

{%html:
<p style="text-align:center;">
<img src="_assets/handle_skline.png" style="width:150mm;"/>
</p> %}

As mentioned above, continuous curvature loops are also possible. Here we
morph cyclically through circular and pentagonal profiles by specifying
[~endcaps:`Loop].

{[
let () =
let circ = Path3.circle ~fn:64 5. in
let pent = Path3.(circle ~fn:5 5.) in
let profs =
Path3.
[ circ
; translate (v3 15. 0. 20.) (yrot (Float.pi /. 2.) pent)
; xtrans 30. (yrot Float.pi circ)
; translate (v3 15. 0. (-20.)) (yrot (Float.pi *. 1.5) pent)
]
in
Mesh.skline ~endcaps:`Loop ~fn:200 ~size:(`Flat (`Rel 0.1)) profs
|> Scad.of_mesh
|> Scad.to_file ~incl:true "edgy_loop.scad"
]}

{%html:
<p style="text-align:center;">
<img src="_assets/edgy_loop.png" style="width:150mm;"/>
</p> %}

1 change: 1 addition & 0 deletions examples/dune
Expand Up @@ -15,6 +15,7 @@
resampled_path
default_vs_euler_sweeps
profile_skinning
spline_skinning
morphing_sweeps)
(libraries OSCADml OCADml.PolyText))

Expand Down
2 changes: 1 addition & 1 deletion examples/morphing_sweeps.ml
Expand Up @@ -15,7 +15,7 @@ let () =
V3.[ v 0. 0. 2.; v 0. 20. 20.; v 40. 20. 10.; v 30. 0. 10. ]
|> Path3.quaternion (Quaternion.make (v3 1. 1. 0.) (Float.pi /. -5.))
in
Bezier3.curve ~fn:60 @@ Bezier3.of_path ~size:(`Flat (`Rel 0.3)) control
Bezier3.curve ~fn:80 @@ Bezier3.of_path ~size:(`Flat (`Rel 0.3)) control
and caps =
Mesh.Cap.(capped ~bot:(round @@ circ (`Radius 0.5)) ~top:(round @@ circ (`Radius 0.5)))
and a = Poly2.ring ~fn:5 ~thickness:(v2 2.5 2.5) (v2 6. 6.)
Expand Down
Binary file modified examples/pngs/arc_points_2d.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified examples/pngs/arc_points_3d.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified examples/pngs/arc_wedge_2d.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified examples/pngs/bezier_spline_path.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified examples/pngs/cartesian_gravity_well.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified examples/pngs/chamfered_loop.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified examples/pngs/chamfered_square_with_holes.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified examples/pngs/circular_rounding.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/pngs/edgy_loop.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified examples/pngs/elbow.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/pngs/handle_points.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/pngs/handle_skline.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified examples/pngs/helix_extrude.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified examples/pngs/helix_path_points.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified examples/pngs/incl_polar_rose.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified examples/pngs/offset_poly.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified examples/pngs/polar_rose.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified examples/pngs/resampled_path.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified examples/pngs/rounded_polyhole_sweep.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified examples/pngs/rounded_prism_star.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified examples/pngs/spiral.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified examples/pngs/sweep_path_default.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified examples/pngs/sweep_path_euler.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified examples/pngs/sweep_starburst_default.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified examples/pngs/sweep_starburst_euler.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified examples/pngs/tangent_morph_sweep.png
Binary file removed examples/pngs/tangent_skin_test.png
Diff not rendered.
Binary file modified examples/pngs/test_hull_3d.png
2 changes: 1 addition & 1 deletion examples/polyholes.ml
Expand Up @@ -22,6 +22,6 @@ let () =
|> Scad.translate (v3 0. 0. (-3.))
|> Scad.color ~alpha:0.5 Color.BlueViolet
in
Scad.union [ poly; reference ]
Scad.add poly reference
in
Scad.to_file "polyholes.scad" scad
16 changes: 3 additions & 13 deletions examples/profile_skinning.ml
Expand Up @@ -12,14 +12,13 @@ open OSCADml
connector. *)

let profiles =
let fn = 32
and up h = Path3.translate (v3 0. 0. h) in
let fn = 32 in
let base =
let sq = Path3.square ~center:true (v2 2. 4.) in
Path3.(roundover ~fn (Round.flat ~corner:(Round.circ (`Radius 0.5)) sq))
and c r h = up h @@ Path3.circle ~fn r in
and c r h = Path3.ztrans h @@ Path3.circle ~fn r in
let cones = List.map (fun h -> [ c 0.6 h; c 0.5 (h +. 1.) ]) [ 4.; 5.; 6. ] in
List.flatten @@ ([ base; up 2. base; c 0.5 3.; c 0.5 4. ] :: cones)
List.flatten ([ base; Path3.ztrans 2. base; c 0.5 3.; c 0.5 4. ] :: cones)

(** A quick look at the points of our profiles we are about to mesh over with
alternating colours may help a bit to conceptualize what we are about to
Expand Down Expand Up @@ -47,12 +46,3 @@ let () =
<img src="_assets/vaccum_connector.png" style="width:150mm;"/>
</p> %}
*)

let () =
Mesh.skin
~refine:2
~slices:(`Flat 25)
~mapping:(`Flat `Tangent)
Path3.[ circle ~fn:5 4.; translate (v3 0. 0. 3.) @@ circle ~fn:80 2. ]
|> Scad.of_mesh
|> Scad.to_file "tangent_skin_test.scad"
4 changes: 2 additions & 2 deletions examples/spline.ml
Expand Up @@ -6,7 +6,7 @@ open OSCADml
(** Control points that our
{{:https://mathworld.wolfram.com/CubicSpline.html}cubic spline} will pass
through. *)
let control = [ v2 0. 10.; v2 10. 40.; v2 20. 40.; v2 30. (-20.); v2 40. (-40.) ]
let control = V2.[ v 0. 10.; v 10. 40.; v 20. 40.; v 30. (-20.); v 40. (-40.) ]

(** Mark our [control] points with the debugging helper
{{!OSCADml.Debug.show_path2} [Debug.show_path2]} for reference. We don't
Expand All @@ -25,7 +25,7 @@ let line =
Scad.of_mesh @@ Mesh.path_extrude ~path rectangle

(** Union our control point [marks] and [line] sweep shapes and output to file. *)
let () = Scad.to_file "spline.scad" (Scad.union [ line; marks ])
let () = Scad.to_file "spline.scad" (Scad.add line marks)

(** {%html:
<p style="text-align:center;">
Expand Down
87 changes: 87 additions & 0 deletions examples/spline_skinning.ml
@@ -0,0 +1,87 @@
(** {0 Bézier Sklines} *)

open OCADml
open OSCADml

(** {{!OCADml.Mesh.skline} [Mesh.skline]}, like {{!OCADml.Mesh.skin}
[Mesh.skin]} provides a means of generating a mesh that covers a series of
given profiles, but where [skin] linearly transistions between each profile
independently, [skline] splines through each of the paths formed by the
associated vertices from the first profile to the last (or in a loop).
to generate meshes that cover over series of profiles. However, unlike
[skin] only resampling is made available for mapping vertices between
incomensurate profiles as the point duplication methods (tangent and
distance) can easily lead to edge intersections. *)

let handle_profiles =
let circ = Path3.circle ~fn:64 5. in
let base = Path3.scale (v3 1.2 1.2 1.) circ
and handle = Path3.scale (v3 0.7 0.7 1.) circ in
Path3.
[ ztrans (-3.) base
; circ
; translate (v3 15. 0. 20.) (yrot (Float.pi /. 2.) handle)
; xtrans 30. (yrot Float.pi circ)
; translate (v3 30. 0. (-3.)) (yrot Float.pi base)
]

(** A quick look at the points of our profiles we are about to spline over with
alternating colours may help a bit to conceptualize what we are about to
give {{!OCADml.Mesh.skline} [Mesh.skline]} to work with. *)
let () =
let show i =
let c = if i mod 2 = 0 then Color.Magenta else Color.Aquamarine in
Debug.show_path3 (fun _ -> Scad.(color c @@ sphere 0.2))
in
List.mapi show handle_profiles |> Scad.union |> Scad.to_file "handle_points.scad"

(** {%html:
<p style="text-align:center;">
<img src="_assets/handle_points.png" style="width:150mm;"/>
</p> %}
*)

(** Using the [?tangents] parameter of {{!OCADml.Bezier3.of_path}
[Bezier3.of_path]} we can specify the tangents we want for each profile,
rather than leaving them up to the automatically computed derivatives (that
may differ for each edge path tracing between the profiles). Here we
contstrain them to cardinals so we can get a handle that sticks closer to
right angles. *)

let () =
let up = v3 0. 0. 1. in
let tangents = `Tangents [ up; up; v3 1. 0. 0.; V3.neg up; V3.neg up ] in
Mesh.skline ~fn:200 ~size:(`Flat (`Rel 0.5)) ~tangents handle_profiles
|> Scad.of_mesh
|> Scad.to_file ~incl:true "handle_skline.scad"

(** {%html:
<p style="text-align:center;">
<img src="_assets/handle_skline.png" style="width:150mm;"/>
</p> %}
*)

(** As mentioned above, continuous curvature loops are also possible. Here we
morph cyclically through circular and pentagonal profiles by specifying
[~endcaps:`Loop]. *)

let () =
let circ = Path3.circle ~fn:64 5. in
let pent = Path3.(circle ~fn:5 5.) in
let profs =
Path3.
[ circ
; translate (v3 15. 0. 20.) (yrot (Float.pi /. 2.) pent)
; xtrans 30. (yrot Float.pi circ)
; translate (v3 15. 0. (-20.)) (yrot (Float.pi *. 1.5) pent)
]
in
Mesh.skline ~endcaps:`Loop ~fn:200 ~size:(`Flat (`Rel 0.1)) profs
|> Scad.of_mesh
|> Scad.to_file ~incl:true "edgy_loop.scad"

(** {%html:
<p style="text-align:center;">
<img src="_assets/edgy_loop.png" style="width:150mm;"/>
</p> %}
*)

0 comments on commit a0a7ef5

Please sign in to comment.