Skip to content

Instantly share code, notes, and snippets.

@ochafik
Last active March 16, 2022 02:38
Show Gist options
  • Select an option

  • Save ochafik/b521b12d4c92b1e6036f9f3bbdca015b to your computer and use it in GitHub Desktop.

Select an option

Save ochafik/b521b12d4c92b1e6036f9f3bbdca015b to your computer and use it in GitHub Desktop.
BOSL2 Smooth Skin + Turtle for OpenSCAD

image

image

image

image

include <BOSL2/std.scad>
include <BOSL2/turtle3d.scad>
include <BOSL2/beziers.scad>

use <smooth_skin.scad>

previewEpsilon = 0.01;//$render ? 0 : 0.01;

translate([200, 0, 0])
    //back_half()
    difference() {
        skin(
            smooth_profiles(
                subdivide_and_slice([
                    path3d(circle(r=40)),
                    path3d(circle(r=50)),
                    path3d(circle(r=40)),
                ], 0),
                steps=10, 
                transforms=[
                    up(0 - previewEpsilon),
                    up(20),
                    //up(35),
                    up(40 + previewEpsilon),
                ],
                speeds=[
                    "fastslow",
                    //"linear",
                    "slowfast",
                ],
            ),
            method="fast_distance",
            slices=0
        );
        skin(
            smooth_profiles(
                subdivide_and_slice([
                    path3d(circle(r=30)),
                    path3d(circle(r=20)),
                    path3d(circle(r=20)),
                    path3d(circle(r=30)),
                    //path3d(circle(5, $fn=3)),
                ], 0),
                steps=10, 
                transforms=[
                    up(0 - previewEpsilon),
                    up(5),
                    up(35),
                    up(40 + previewEpsilon),
                ],
                speeds=[
                    "fastslow",
                    "linear",
                    "slowfast",
                    "fastfast",
//                    "slowfast",
                ],
            ),
            method="fast_distance",
            slices=0
        );
    }

Another:

include <BOSL2/std.scad>
include <BOSL2/structs.scad>
include <BOSL2/rounding.scad>

id=14;
od=20;
or=od/2;
leg_length=30;
thickness=6;
hole_round_r=1;
center=[or, leg_length - or];
holefront=center - [0, id/2];

echo(arc(width=od, thickness=od/2));
//circle(d=od, anchor=FRONT) {
//    attach(CENTER) 
//        square([od, leg_length - od / 2], anchor=BACK);
//}

function hull_polys(pts) =
    [for (i=hull(pts)) pts[i]];
    
function plate(insets=0, hole=false) =
    let (radius=or - insets)
      hole
      ? apply(
            translate(center),
//            circle(id / 2 + insets)
            teardrop2d(id / 2 + insets)
        )
      : 
//      struct_set([], [
//        "path",
        round_corners(
            hull_polys(concat(
                apply(translate(center), teardrop2d(d=od - 2*insets)),
                //teardrop2d(d=od - 2*insets),
                apply(translate([od/2, 0]), arc(10, width=od, thickness=od/2)),
                //square([od, or/10]),
                //apply(translate([insets, 0, 0]), square([od - 2 * insets, leg_length - or])),
            ))
            , radius=2
        )
        ;
//        turtle([
//            "move", od - insets,
//            "left",
//            "move", center.y,
//            "arcsteps", 20,
//            "arcleft", radius, 180,
//            "move", center.y,
//        ]),
//      ]);   
  
//function geom_get_path(geom) =
//    struct_val(geom, "path");
//function geom_get_attachment(geom, name) =
//    struct_val(struct_val(geom, "attachments"), name);

use <smooth_skin.scad>

previewEpsilon = 0.1;//$render ? 0 : 0.01;

//translate([0, 0, 0])
module hole()
    //back_half()
    top_half()
    mirror([0, 1, 0]) {
        *skin(
            smooth_profiles(
                subdivide_and_slice([
                    path3d(apply(translate([-od/2, -thickness]), square([od, thickness]))),
                    path3d(apply(translate([-od, -3*thickness]), square([2*od, 3*thickness]))),
                ], 0),
                steps=10, 
                transforms=[
                    xrot(-45),
                    up(0),
                ],
                transitions=[
                    "slowfast",
                ],
            ),
            method="distance",
            slices=0
        );
        xrot(45) translate(-holefront)
    //    translate(-geom_get_attachment(plate(0), "holefront"))
        difference() {
            skin(
                smooth_profiles(
                    subdivide_and_slice([
                        path3d(plate(2)),
                        path3d(plate(0)),
                        path3d(plate(2)),
                    ], 0),
                    steps=10, 
                    transforms=[
                        up(0 - previewEpsilon),
                        up(thickness / 2),
                        up(thickness + previewEpsilon),
                    ],
                    transitions=[
                        "fastslow",
                        //"linear",
                        "slowfast",
                    ],
                ),
                method="distance",
                slices=0
            );
            skin(
                smooth_profiles(
                    subdivide_and_slice([
                        path3d(plate(2, hole=true)),
                        path3d(plate(0, hole=true)),
                        path3d(plate(0, hole=true)),
                        path3d(plate(2, hole=true)),
                    ], 0),
                    steps=10, 
                    transforms=[
                        up(0 - previewEpsilon),
                        up(hole_round_r),
                        up(thickness - hole_round_r),
                        up(thickness + previewEpsilon),
                    ],
                    transitions=[
                        "fastslow",
                        "linear",
                        "slowfast",
                    ],
                ),
                method="distance",
                slices=0
            );
            *skin(
                smooth_profiles(
                    subdivide_and_slice([
                        path3d(circle(r=30)),
                        path3d(circle(r=20)),
                        path3d(circle(r=20)),
                        path3d(circle(r=30)),
                        //path3d(circle(5, $fn=3)),
                    ], 0),
                    steps=10, 
                    transforms=[
                        up(0 - previewEpsilon),
                        up(5),
                        up(35),
                        up(40 + previewEpsilon),
                    ],
                    transitions=[
                        "fastslow",
                        "linear",
                        "slowfast",
                        "fastfast",
    //                    "slowfast",
                    ],
                ),
                method="fast_distance",
                slices=10
            );
        }
    }

module pole() {
    mirror([0, 1, 0])
    skin(
        smooth_profiles(
            subdivide_and_slice([
                path3d(apply(translate([-plate_size/2, -plate_size]), square([plate_size, plate_size]))),
                path3d(apply(translate([0, -pole_d/2]), circle(d=pole_d))),
                path3d(apply(translate([0, -pole_d/2]), circle(d=pole_d))),
                path3d(apply(translate([0, -pole_d*f/2]), circle(d=f*pole_d))),
                path3d(apply(translate([0, -pole_d]), circle(d=pole_d))),
            ], 0),
            steps=20, 
            transforms=[
                up(0),
                xrot(-45),
                xrot(-45) * translate([0, 0, pole_len]),
                xrot(-45) * translate([0, 0, pole_len + thickness / 2]),
                xrot(-45) * translate([0, 0, pole_len + thickness]),
            ],
            transitions=[
                "fastslow",
                "linear",
                "slowslow",
                "slowfast",
            ],
        ),
        method="fast_distance",
        slices=10
    );
}

plate_size=40;
//cube([plate_size, plate_size, thickness], anchor=TOP+FRONT);
hole();
translate([0, plate_size, 0]) mirror([0, 1, 0]) pole();
translate([plate_size/2, plate_size/2, 0]) zrot(90) pole();
translate([-plate_size/2, plate_size/2, 0]) mirror([1, 0, 0]) zrot(90) hole();

plate_top=
    path3d(
        apply(
            translate([0, plate_size/2]),
            round_corners(
                square(plate_size, center=true),
                radius=2
            )
        )
    );
    
skin(
    smooth_profiles(
        subdivide_and_slice([
            plate_top,
            path3d(
                apply(
                    translate([0, plate_size/2]),
                    round_corners(
                        square(plate_size - 2, center=true),
                        radius=2
                    )
                )
            ),
        ], 0),
        steps=20, 
        transforms=[
            down(thickness),
            up(0),
        ],
        transitions=[
            "slowfast",
        ],
    ),
    method="fast_distance",
    slices=10
);

wiggle=4;
pole_d=id - wiggle;
pole_len=2*thickness;

f=1.5;

translate([0, -wiggle/2, 0])
mirror([0, 1, 0]) 
pole();
include <BOSL2/std.scad>
include <BOSL2/beziers.scad>
include <BOSL2/turtle3d.scad>
function slowFast(x) =
1 - sqrt(1 - pow(x, 2));
function fastSlow(x) =
sqrt(1 - pow(x - 1, 2));
function fastFast(x) =
(x < 0.5)
? sqrt(0.25 - pow(x - 0.5, 2))
: 1 - sqrt(0.25 - pow(x - 0.5, 2));
function slowSlow(x) =
(x < 0.5)
? 0.5 - sqrt(0.25 - pow(x, 2))
: 0.5 + sqrt(0.25 - pow(x - 1, 2));
echo("fastfast", [for (i=[0:10]) fastFast(i/10)]);
echo("fastslow", [for (i=[0:10]) fastSlow(i/10)]);
echo("slowfast", [for (i=[0:10]) slowFast(i/10)]);
echo("slowslow", [for (i=[0:10]) slowSlow(i/10)]);
function getTranslation(t) =
[
(t * [1, 0, 0, 1]).xyz - [1, 0, 0],
(t * [0, 1, 0, 1]).xyz - [0, 1, 0],
(t * [0, 0, 1, 1]).xyz - [0, 0, 1],
];
function getScale(t) =
[
norm((t * [1, 0, 0, 1]).xyz),
norm((t * [0, 1, 0, 1]).xyz),
norm((t * [0, 0, 1, 1]).xyz),
];
valid_speeds = ["slowslow", "slowfast", "fastslow", "fastfast"];
function smooth_profiles(profiles, transforms, speeds="slowslow", steps=10, orig=[0, 0, 0, 1], up=[0, 0, 1, 1]) = [
for (i=[0:len(transforms)-2])
let (steps=is_list(steps) ? steps[i] : steps,
speed=is_list(speeds) ? speeds[i] : speeds,
t1=transforms[i],
t2=transforms[i+1],
// s1=getScale(t1),
// s2=getScale(t2),
p1=profiles[i],
p2=profiles[i+1]
// o1=(t1 * orig).xyz,
// o2=(t2 * orig).xyz,
// up1=(t1 * up).xyz - o1,
// up2=(t2 * up).xyz - o2,
// q1=q_from_to(up.xyz, up1),
// q2=q_from_to(up1, up2),
// dist=norm(o2 - o1),
// bezCtl1=o1 + up1 * dist / 10,
// bezCtl2=o2 - up2 * dist / 10,
// bez=[o1, bezCtl1, bezCtl2, o2]
)
// [o1, up1, o2, up2, q1, q2, p1, p2]
for (i=[0:steps])
let (f=i/steps,
u=speed=="slowslow" ? slowSlow(f)
: speed=="fastfast" ? fastFast(f)
: speed=="fastslow" ? fastSlow(f)
: speed=="slowfast" ? slowFast(f)
: f
// bezPt=bezier_points(bez, f),
// bezTan=bezier_tangent(bez, f),
// bezQ=q_from_to(up.xyz, bezTan)
)
// [f, bez, bezTan, bezQ]
apply(
// https://github.com/revarbat/BOSL2/wiki/beziers.scad#function-bezier_points
// translate(bezPt) * q_rot(bezQ),
lerp(t1, t2, f),
// https://github.com/revarbat/BOSL2/wiki/quaternions.scad#function-q_from_to
// translate(lerp(o1, o2, f)) * q_rot(q_slerp(q1, q2, f)),
lerp(p1, p2, u))
];
function smooth_turtle3d(
args,
state=RIGHT,
turtle=[],
transforms_offset=1,
speed="slowslow",
profiles=[],
speeds=[],
transformss=[]) =
len(args) == 0
? [profiles, speeds, transformss, turtle]
: let (command=args[0])
command == "profile" && len(args) > 1
? let(profile=args[1],
turtle_transforms=turtle3d(turtle, transforms=true, state=state),
profile_transforms=slice(turtle_transforms, transforms_offset))
smooth_turtle3d(
list_tail(args, 2),
state=state,
turtle=turtle, // Keep it alive
speed=speed,
transforms_offset=
transforms_offset+len(profile_transforms),
profiles=concat(profiles, profile),
speeds=concat(speeds, speed),
transformss=concat(
transformss,
[profile_transforms]
)
)
: in_list(command, valid_speeds)
? smooth_turtle3d(
list_tail(args, 1),
state=state,
turtle=turtle,
speed=command,
profiles=profiles,
speeds=speeds,
transformss=transformss)
: smooth_turtle3d(
list_tail(args, 1),
state=state,
turtle=concat(turtle, command),
speed=speed,
profiles=profiles,
speeds=speeds,
transformss=transformss);
res=smooth_turtle3d([
"profile", [123],
"up",
"move", 10,
"profile", [456],
"arcleft", 45,
"profile", [789],
]);//, state=zmove(-10));
echo("smooth turtle", res);
echo("turtle", res[3]);
for (t=res[2])
echo("Transform", t);
// echo(len(res[2]));
// basePoly = [for (v=[
// [-1, 0],
// [-1, 1],
// [2, 0],
// [1, 1],
// [1, 0],
// ]) v * 100];
// echo(path3d(basePoly));
// original_profiles = subdivide_and_slice([
// //path3d(basePoly),
// path3d(square(10*width, anchor=FRONT)),
// //// path3d(Section(5)),
// path3d(Section(4)),
// path3d(Section(1)),
// // path3d(square(1)),
// path3d(Section(2)),
// path3d(Section(1)),
// ], 0);
// transforms = [
// translate([0, 0, -10]),
// translate([1, 0, 1]),
// xrot(45) * translate([0, 0, 10]),
// translate([0, -10, 10]) * xrot(45) * translate([0, 0, 10]),
// translate([0, -12, 12]) * xrot(45) * translate([0, 0, 10]) * translate([0, 0, 0]),
// ];
// smoothed_profiles = smooth_profiles(original_profiles, transforms, steps=10, speeds=["slowfast", "fastslow", "slowslow", "slowfast"]);
// //if (false) {
// if (smooth) {
// skin(smoothed_profiles, method="fast_distance", slices=2);
// } else {
// skin(
// [for (i=[0:len(original_profiles)-1]) apply(transforms[i], original_profiles[i])],
// method="reindex",
// slices=0);
// }
//}
//r = 0.25;
////$f=30;
//t=["up",25,"move","arcleft",r,"move",3,"arcleft",r,"move","arcleft",r,"move",3,"arcleft",r];
//echo(turtle3d(t, transforms=true));
//stroke(turtle3d(t),closed=true, width=.2);
//stroke(path,closed=true, width=.2));
//echo(translate([1, 1, 1]) * [0, 0, 1, 1]);
//echo(interpolateProfiles([[[0, 0, 0]], [[1, 1, 1]]], 10));
//echo(interpolateProfiles(profiles, sections));
//skin([
// path3d(Section(4)),
// xrot(45, p=path3d(Section(1), 10)),
// xrot(45, p=path3d(Section(1), 20)),
// xrot(45, p=path3d(scale(1.9, p=Section(1)), 24)),
// xrot(45, p=path3d(scale(1.9, p=Section(1)), 26)),
// //xrot(45, p=path3d(circle(d=width), 10)),
//], method="reindex",slices=10);
//echo(hull(apply(translate([i*width/2, 0, 0]), circle(r=edgeR)));
//hull2d([
//
//hull() {
// translate([0, depth, 0]) circle(r=edgeR);
// for (i=[-1,1])
// translate([i*width/2, 0, 0])
// circle(r=edgeR);
//}
//echo(circle(1));
//echo(hull2d_path(pts));
//echo([for (i=hull2d_path(pts)) pts[i]]);
//echo(yrot(37,p=path3d(circle($fn=128, r=4))));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment