Creating fingerjoint boxes using Sketchup

Hello
Just wanted to tip you off in case you want to create e.g. fingerjoint boxes in Sketchup. I have been searching a lot to find the best solutions and here is my “recipe”. If anyone have better solutions please give your comments!

  • Download OpenScad - and use the script attached below to create the box with your measurements. Source: Customizable Box with Finger Joints by txoof - Thingiverse
  • Export the result to a DXF file in OpenScad
  • Import the DXF in Sketchup.
  • Go to Extension warehouse and look up this excellent tool by thomthom: Milling tools to create dog-bone joints.
  • You need to do some minor editing to the DXF imported to make closed faces. When this is completed you can use the Milling tool to auto-create dog-bones…really really cool :smiley: Remember to have the correct facing (reverse faces if result is not as expected). You also of course need to take a standing on the toolbit diameter at this stage.
  • After the box “skeleton” is completed do your adjustments to the box (button holes, openings, whatever).
  • Export the faces to SVG using this excellent tool: Sketchup SVG Outline Plugin by simonbeard
  • Import to Easel or Makercam and start carving :smiley:

HERE IS THE SCRIPT FOR OPENSCAD:

/*
Create an outline for a laser cut box with finger joints
Released under the Creative Commons Attribution License
Some Rights Reserved: aaron . ciuffo 2 gmail.com

Version 3.0 12 November 2014
  * rewrite from scratch
  * removed kerf all together

Version 3.1 13 November 2014
  * reworked layout2D to handled a greater variety of part sizes

Version 3.2 13 November 2014
  * verified that removing kerf handling was a good idea
  * fixed small issue with layout2D
  * cookies?

Version 3.3 15 November 2014
  * fixed a few typos - Thanks Mixomycetes for pointing those out

*/

/*[Box Outside Dimensions]*/
//Box Width - X
bX=120;
//Box Depth - Y
bY=250;
//Box Height - Z
bZ=100;
//Material Thickness
thick=7;

/*[Box Features]*/
//Include a lid?
addLid=1; //[1:Lid, 0:No Lid]
//Finger Hole Diameter - 0==no hole
holeDia=10; //[0:50]
holeFacets=36;//[3:36]

/*[Finger Width]*/
//Finger width (NB! width must be < 1/3 shortest side)
fingerW=10;//[3:20]
//Lid finger width 
fingerLidW=10;//[3:20]
//Laser kerf
kerf=0.1;

/*[Layout]*/
//separation of finished pieces
separation=1;
//transparency of 3D model
alpha=50; //[1:100]
2D=1; //[1:2D for DXF, 0:3D for STL]

/*[Hidden]*/
//transparency alpha
alp=1-alpha/100;






//cuts that fall complete inside the edge
module insideCuts(length, fWidth, cutD, uDiv) {
  //Calculate the number of fingers and cuts
  numFinger=floor(uDiv/2);
  numCuts=ceil(uDiv/2);

  //draw out rectangles for slots
  for (i=[0:numCuts-1]) {
    translate([i*(fWidth*2), 0, 0])
      square([fWidth, cutD]);
  }
}

//cuts that fall at the end of an edge requirng an extra long cut
module outsideCuts(length, fWidth, cutD, uDiv) {
  numFinger=ceil(uDiv/2);
  numCuts=floor(uDiv/2);
  //calculate the length of the extra long cut
  endCut=(length-uDiv*fWidth)/2;
  //amount of padding to add to the itterative placement of cuts 
  // this is the extra long cut at the beginning and end of the edge
  padding=endCut+fWidth;
  
  square([endCut, cutD]);

  for (i=[0:numCuts]) {
    if (i < numCuts) {
      translate([i*(fWidth*2)+padding, 0, 0])
        square([fWidth, cutD]);
    } else {
      translate([i*(fWidth*2)+padding, 0, 0])
        square([endCut, cutD]);
    }
  }


  
}



//Face A (X and Z dimensions)
//Front and back face
module faceA(uDivX, uDivY, uDivZ, uDivLX, uDivLY) {
  difference() {
    square([bX, bZ], center=true);

    //X+/- edge (X axis in OpenSCAD)
    //if true, make cuts for the lid, otherwise leave a blank edge
    if (addLid) {
      translate([-uDivLX*fingerLidW/2, bZ/2-thick, 0])
        insideCuts(len=bX, fWidth=fingerLidW, cutD=thick, uDiv=uDivLX);
    }
    translate([-uDivX*fingerW/2, -bZ/2, 0]) 
      insideCuts(length=bX, fWidth=fingerW, cutD=thick, uDiv=uDivX);

    //Z+/- edge (Y axis in OpenSCAD)
    translate([bX/2-thick, uDivZ*fingerW/2, 0]) rotate([0, 0, -90])
      insideCuts(length=bZ, fWidth=fingerW, cutD=thick, uDiv=uDivZ);
    translate([-bX/2, uDivZ*fingerW/2, 0]) rotate([0, 0, -90])
      insideCuts(length=bZ, fWidth=fingerW, cutD=thick, uDiv=uDivZ);

  }
}

//Face B (X and Y dimensions)
//Lid and base
module faceB(uDivX, uDivY, uDivZ, uDivLX, uDivLY, makeLid=0) {

  //if this is the "lid" use fingerLidW dimensions instead of fingerW
  //create the local version of these variables

  uDivXloc= makeLid==1 ? uDivLX : uDivX;
  uDivYloc= makeLid==1 ? uDivLY : uDivY;
  fingerWloc= makeLid==1 ? fingerLidW : fingerW;
  lidHoleLoc= makeLid==1 ? holeDia/2 : 0;

  difference() {
    square([bX, bY], center=true);

    //X+/- edge
    translate([-bX/2, bY/2-thick, 0])
      outsideCuts(length=bX, fWidth=fingerWloc, cutD=thick, uDiv=uDivXloc);
    translate([-bX/2, -bY/2, 0])
      outsideCuts(length=bX, fWidth=fingerWloc, cutD=thick, uDiv=uDivXloc);

    //Y+/- edge
    translate([bX/2-thick, uDivYloc*fingerWloc/2, 0]) rotate([0, 0, -90])
      insideCuts(length=bY, fWidth=fingerWloc, cutD=thick, uDiv=uDivYloc);
    translate([-bX/2, uDivYloc*fingerWloc/2, 0]) rotate([0, 0, -90])
      insideCuts(length=bY, fWidth=fingerWloc, cutD=thick, uDiv=uDivYloc);
  
    //lid hole with holeFacets sides
    circle(r=lidHoleLoc, $fn=holeFacets);
  }
  
}

//Face C (Z and Y dimensions)
//left and right sides
module faceC(uDivX, uDivY, uDivZ, uDivLX, uDivLY) {

  difference() {
    square([bY, bZ], center=true);
    
    //Y+/- edge (X axis in OpenSCAD)
    //make cuts for the lid or leave a straight edge
    if(addLid) {
      translate([-bY/2, bZ/2-thick, 0])
        outsideCuts(length=bY, fWidth=fingerLidW, cutD=thick, uDiv=uDivLY);  
    }
    translate([-bY/2, -bZ/2, 0])
      outsideCuts(length=bY, fWidth=fingerW, cutD=thick, uDiv=uDivY);

    //Z+/- edge (Y axis in OpenSCAD)
    translate([bY/2-thick, bZ/2, 0]) rotate([0, 0, -90])
      outsideCuts(length=bZ, fWidth=fingerW, cutD=thick, uDiv=uDivZ);
    translate([-bY/2, bZ/2, 0]) rotate([0, 0, -90])
      outsideCuts(length=bZ, fWidth=fingerW, cutD=thick, uDiv=uDivZ);
      

  }
}

module layout2D(uDivX, uDivY, uDivZ, uDivLX, uDivLY) {
  yDisplace= bY>bZ ? bY : bZ+separation;

  translate([])
    color("red") faceA(uDivX, uDivY, uDivZ, uDivLX, uDivLY);
  translate([bX+separation+bY+separation, 0, 0])
    color("darkred") faceA(uDivX, uDivY, uDivZ, uDivLX, uDivLY);



  translate([bX/2+bY/2+separation, 0, 0])
    color("blue") faceC(uDivX, uDivY, uDivZ, uDivLX, uDivLY);
  //bottom row
  translate([bX/2+bY/2+separation, -yDisplace, 0])
    color("darkblue") faceC(uDivX, uDivY, uDivZ, uDivLX, uDivLY);



  if (addLid) {
    //bottomo row
    translate([0, -bZ/2-yDisplace/2-separation, 0])
      color("lime") faceB(uDivX, uDivY, uDivZ, uDivLX, uDivLY, makeLid=1);
  }
  translate([bX+separation+bY+separation, -bZ/2-yDisplace/2-separation, 0])
    color("green") faceB(uDivX, uDivY, uDivZ, uDivLX, uDivLY, makeLid=0);
}

module layout3D(uDivX, uDivY, uDivZ, uDivLX, uDivLY, alp=0.5) {
  //amount to shift for cut depth 
  D=thick/2;


  //bottom of box (B-)
  color("green", alpha=alp)
    translate([0, 0, 0])
    linear_extrude(height=thick, center=true) faceB(uDivX, uDivY, uDivZ, uDivLX, 
      uDivLY, makeLid=0);

  if (addLid) {
    color("lime", alpha=alp)
      translate([0, 0, bZ-thick])
      linear_extrude(height=thick, center=true) faceB(uDivX, uDivY, uDivZ, uDivLX, 
        uDivLY, makeLid=1);
  }

  color("red", alpha=alp)
    translate([0, bY/2-D, bZ/2-D]) rotate([90, 0, 0])
    linear_extrude(height=thick, center=true) faceA(uDivX, uDivY, uDivZ, uDivLX, 
      uDivLY);

  color("darkred", alpha=alp)
    translate([0, -bY/2+D, bZ/2-D]) rotate([90, 0, 0])
    linear_extrude(height=thick, center=true) faceA(uDivX, uDivY, uDivZ, uDivLX, 
      uDivLY);
   
  color("blue", alpha=alp)
    translate([bX/2-D, 0, bZ/2-D]) rotate([90, 0, 90])
    linear_extrude(height=thick, center=true) faceC(uDivX, uDivY, uDivZ, uDivLX, 
      uDivLY);
  color("darkblue", alpha=alp)
    translate([-bX/2+D, 0, bZ/2-D]) rotate([90, 0, 90])
    linear_extrude(height=thick, center=true) faceC(uDivX, uDivY, uDivZ, uDivLX, 
      uDivLY);
  

}


module main() {
  //Calculate the maximum number of fingers and cuts possible
  maxDivX=floor(bX/fingerW);
  maxDivY=floor(bY/fingerW);
  maxDivZ=floor(bZ/fingerW);

  //Calculate the max number of fingers and cuts for the lid
  maxDivLX=floor(bX/fingerLidW);
  maxDivLY=floor(bY/fingerLidW);

  //the usable divisions value must be odd for this layout
  uDivX= (maxDivX%2)==0 ? maxDivX-3 : maxDivX-2;
  uDivY= (maxDivY%2)==0 ? maxDivY-3 : maxDivY-2;
  uDivZ= (maxDivZ%2)==0 ? maxDivZ-3 : maxDivZ-2;
  uDivLX= (maxDivLX%2)==0 ? maxDivLX-3 : maxDivLX-2;
  uDivLY= (maxDivLY%2)==0 ? maxDivLY-3 : maxDivLY-2;

  if(2D) {
    layout2D(uDivX, uDivY, uDivZ, uDivLX, uDivLY);
  } else {
    layout3D(uDivX, uDivY, uDivZ, uDivLX, uDivLY);
  }
}

main();
2 Likes

Have you seen any of the easy box generator apps like Makercase or makeabox.io? Both of those are super simple to use and spit out an .svg which you directly import into Easel.

You have the option of a couple of different types of joints, including finger joints.

4 Likes

Hi michael, no I have not. Thanks for the Tip!! I am new to easel, I have used makercam before. Will check it out :slight_smile:

Wow, that works really well, made this in about 5 minutes. I wonder though, how well the corners would come out because of the round bit.

http://easel.inventables.com/projects/GW9DAkusUnKVXdKUefllpQ

Someone needs to make a CNC version of those!

(@DallasPowers Need to go to “File”->“Share” and set the project to public if you want others to be able to see it)

Fixed…Thanks!

I have found that if you use a medium-soft wood and a 1/16" bit, it’s usually close enough to knock together with a rubber mallet. That and a little glue makes for a sturdy box :slight_smile:

The next step here would be to add dogbones to the corners to account for the bit radius. One of our programmers was working on that a while back, pretty sure it’s still on the agenda to add to Easel.

We’re also talking about building an app like this into Easel directly.

5 Likes

+1 on the feature into Easel.

Yah, it wouldn’t be to hard to chisel the corners clean or use a rasp.

I’d just like to go on record as a being staunch supporter of any assembly method that includes the phrase “knock together with a rubber mallet.”

1 Like

Reminds me of a conversation I heard walking past two of our maintenance guys talking about a machine they had scattered all over the floor:
First mechanic: “I just can’t seem to get it fixed!”
Second mechanic: “That means you’re not using a big enough hammer.”

I agree this would be a great addition to Easel. Save a bunch of “Go here generate the pattern, go back to Easel and import it, re-size it and hope you didn’t mess anything up.”

I’m all for making things simpler for me :smiley:

It would be great if Easel could provide a dogbone feature - but until then I think I will opt for Sketchup/milling tools. I had a look at the links provided by @MichaelUna - they are great for creating simple boxes, but not if you want to do some tweaking on them before carving (for example a project box with button holes, opening for fan, cables etc).

Hey, This is Aaron Ciuffo (Txoof) that created the thing you referenced.

To ease your workflow a bit, you can also use the 3D layout option to create stl files that may be easier to import into SketchUp directly.

I’m having problems getting this extension to work in Sketchup 2015. Has anyone else had this problem? I’ve downloaded and added it to my extensions. I then click on the ungrouped face that I want but when I go to say save out it never exports. I’m not sure what I’m doing wrong. Any help would be appreciated.

Hm that’s strange, I’m using sketchup 2015 and have no issues. Have you changed any of the default settings? It is a closed face you are trying to export? 32/64 bit issues?

Hi Aaron
Thanks for your excellent script! Actually the work flow is not complex at all so I don’t feel the need to change it. When you get the hang of it you can create the faces in your tool, import to sketchup and add dogbones and make it ready for carving in just minutes :slight_smile:

I haven’t change any settings other then mm to inches. You asked about 32/64 issues, I’m using a Mac. Could that be the issue?

Thanks

So uninstalled and installed a different plugin i got from this site using these directions. Sketchup says it’s install but it doesn’t show in the main window or under extensions. Very frustrating, I’m comfortable with Sketchup and I don’t want to take the time to learn another program. I’m close to upgrading to the Pro even through I only need svg export capability.

Hi Rleadams - guess it’s almost cheaper to buy a windows machine than the PRO version! Well - I also run Shetchup on a mac as well, but not sure if it is the 2015 version…I can check when I’m back from work.

Just out of curiosity what do you use Sketchup for? Only CNC or for 3D modelling as well? I was having the same view as you - did not see any need for learning another program, but then I gave OnShape a try…it was an eye opener to what 3D modelling should be - having 3D modelling “thinking” in the back you will only spend some hours to get up to speed - and you can create stuff in minutes that you would use hours to do in Sketchup. And the strength of a parametric SW is incredible - if you need to do small adjustments you do not need to redraw the whole object. Btw still love Sketchup but now I use it most for 2D modelling…at least until OnShape support svg export out of the box :smiley:

Brgds
Christian