Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
b8959f8e5This file is pinned to the selected release. Download the original to open it in your design tool.
/*
Created by Andy Levesque
Credit to @David D on Printables and Jonathan at Keep Making for Multiconnect and Multiboard, respectively
Licensed Creative Commons 4.0 Attribution Non-Commercial - Sharable with Attribution
NOTE: This module may break if the child of another object subject to diff(), intersect(), or union().
Instead, attach to an object
For example:
cuboid([1]){
somthing else;
attach() multiconnectGenerator()
}
NOT:
cuboid([1])
attach() multiconnectGenerator()
https://github.com/BelfrySCAD/BOSL2/issues/270
*/
include <BOSL2/std.scad>
/*[Standard Parameters]*/
//Profile
Select_Profile = "Standard"; //[Standard, Jr., Mini, Multipoint Beta, Custom]
Select_Part_Type = "Connector Round"; //[Connector Round, Connector Rail, Connector Double sided Round, Connector Double-Sided Rail, Connector Rail Delete Tool, Receiver Open-Ended, Receiver Passthrough, Backer Open-Ended, Backer Passthrough]
//Generate one of each part type of the selected profile
One_of_Each = false;
//Generate one of each part type of every profile, including custom
One_of_Everything = false;
//Generate one of each type of part
//Length of rail (in mm) (excluding rounded ends)
Length = 50;
//Add dimples for position locking
Dimples = "Enabled";//[Enabled, Disabled]
//Change the scale (as a multiplier) of dimple size
Dimple_Scale = 1; //[0.5: 0.25: 1.5]
/*[Rail Customization]*/
//Rounding of rail ends
Rounding = "Both Sides";//[None, One Side, Both Sides]
/*[Receiver Customization]*/
Receiver_Side_Wall_Thickness = 2.5;
Receiver_Back_Thickness = 2;
Receiver_Top_Wall_Thickness = 2.5;
OnRamps = "Enabled"; //[Enabled, Disabled]
OnRamp_Every_n_Holes = 2;
OnRamp_Start_Offset = 1;
/*[Backer Customization]*/
Width = 75;
/*[AdvancedParameters]*/
//Distance (in mm) between each grid (25 for Multiboard)
Grid_Size = 25;
/*[Custom MC Builder]*/
//Radius of connector
Radius = 10; //.1
//Depth of inside capture
Depth1 = 1; //.1
//Lateral depth of angle dovetail
Depth2 = 2.5; //.1
//Depth of stem
Depth3 = 0.5; //.1
//Offset/Tolerance of receiver part
Offset = 0.15; //.01
//Radius (in mm) of dimple. Default for standard Multiconnect is 1mm radius (2mm diameter)
DimpleSize = 1; //.1
/* [Hidden] */
debug = false;
//
//BEGIN Start Stand-alone part generator
//
profileList = ["Standard", "Jr.", "Mini", "Multipoint Beta", "Custom"];
partList = ["Connector Round", "Connector Double sided Round", "Connector Rail", "Connector Double-Sided Rail", "Connector Rail Delete Tool", "Receiver Open-Ended", "Receiver Passthrough"]; //removed backers due to performance issues , "Backer Open-Ended", "Backer Passthrough"
if(One_of_Everything){
for(n = [0 : 1 : len(profileList)-1]){
for(i = [0 : 1 : len(partList)-1]){
echo(str("Generating Profile: ", profileList[n], "; Part: ", partList[i]));
fwd((n)*25)
left(partList[i] == "Backer Open-Ended" ? Width*2+(i+1)*27 : (i+1)*27)
GeneratePart(profileList[n], partList[i], Dimples, OnRamps);
}
}
}
else if(One_of_Each){
for(i = [0 : 1 : len(partList)-1])
left(
partList[i] == "Backer Open-Ended" ? Width/2+(i+1)*27 :
partList[i] == "Backer Passthrough" ? Width+27+(i+1)*27 :
(i+1)*27
)
GeneratePart(Select_Profile, partList[i], Dimples, OnRamps);
}
else GeneratePart(Select_Profile, Select_Part_Type, Dimples, OnRamps);
//
//END Stand-alone part generator
//
//
//BEGIN Multiconnect Modules and Functions
//
module GeneratePart(Width, Length, Select_Profile, Select_Part_Type, Dimples, OnRamps){
//unadjusted cordinates, dimple size, default offset
customSpecs = [Radius, Depth1, Depth2, Depth3, Offset, DimpleSize];
standardSpecs = [10, 1, 2.5, 0.5, 0.15, 1];
jrSpecs = [5, 0.6, 1.2, 0.4, 0.16, 0.8];
miniSpecs = [3.2, 1, 1.2, 0.4, 0.16, 0.8];
multipointBeta = [7.9, 0.4, 2.2, 0.4, 0.15, 0.8];
dimplesEnabled =
Dimples == "Enabled" ? true :
false;
onRampEnabled =
OnRamps == "Enabled" ? true :
false;
onRampEveryNHoles = OnRamp_Every_n_Holes * Grid_Size;
onRampOffset = OnRamp_Start_Offset * Grid_Size;
//if part is intended for a receiver, apply offset
isOffset =
Select_Part_Type == "Receiver Open-Ended" ? true :
Select_Part_Type == "Receiver Passthrough" ? true :
Select_Part_Type == "Connector Rail Delete Tool" ? true :
Select_Part_Type == "Backer Open-Ended" ? true :
Select_Part_Type == "Backer Passthrough" ? true :
false;
profile =
Select_Profile == "Standard" ? [dimensionsToCoords(standardSpecs[0], standardSpecs[1], standardSpecs[2], standardSpecs[3], isOffset ? standardSpecs[4] : 0), standardSpecs[5]] :
Select_Profile == "Jr." ? [dimensionsToCoords(jrSpecs[0], jrSpecs[1], jrSpecs[2], jrSpecs[3], isOffset ? jrSpecs[4] : 0), jrSpecs[5]] :
Select_Profile == "Mini" ? [dimensionsToCoords(miniSpecs[0], miniSpecs[1], miniSpecs[2], miniSpecs[3], isOffset ? miniSpecs[4] : 0), miniSpecs[5]] :
Select_Profile == "Multipoint Beta" ? [dimensionsToCoords(multipointBeta[0], multipointBeta[1], multipointBeta[2], multipointBeta[3], isOffset ? multipointBeta[4] : 0), multipointBeta[5]] :
Select_Profile == "Custom" ? [dimensionsToCoords(customSpecs[0], customSpecs[1], customSpecs[2], customSpecs[3], isOffset ? customSpecs[4] : 0), customSpecs[5]] :
[];
if(Select_Part_Type == "Connector Round"){
//echo(str("Generating: ", Select_Part_Type));
rail(0,profile[0], dimplesEnabled = dimplesEnabled, dimpleSize = profile[1], dimpleScale = Dimple_Scale, distanceBetweenDimples = Grid_Size, spin=[90,0,0], anchor=FRONT)
attach([TOP, BOT], BOT, overlap=0.01)
roundedEnd(profile[0], dimplesEnabled = dimplesEnabled, dimpleSize = profile[1], dimpleScale = Dimple_Scale);
}
else if(Select_Part_Type == "Connector Rail"){
//echo(str("Generating: ", Select_Part_Type));
rail(Length, profile[0], onRampEnabled = onRampEnabled, dimpleSize = profile[1], dimplesEnabled = dimplesEnabled, dimpleScale = Dimple_Scale, distanceBetweenDimples = Grid_Size)
if(Rounding != "None")
attach(Rounding == "Both Sides" ? [TOP, BOT] : TOP, BOT, overlap=0.01)
roundedEnd(profile[0], dimplesEnabled = dimplesEnabled, dimpleSize = profile[1], dimpleScale = Dimple_Scale);
}
else if(Select_Part_Type == "Connector Double sided Round"){
//echo(str("Generating: ", Select_Part_Type));
rail(0,profile[0], dimplesEnabled = dimplesEnabled, dimpleSize = profile[1], dimpleScale = Dimple_Scale, distanceBetweenDimples = Grid_Size, spin=[90,0,0], anchor=FRONT)
attach([TOP, BOT], BOT, overlap=0.01)
roundedEnd(profile[0], dimplesEnabled = dimplesEnabled, dimpleSize = profile[1], dimpleScale = Dimple_Scale)
attach(FRONT, FRONT, overlap=0.01)
roundedEnd(profile[0], dimplesEnabled = dimplesEnabled, dimpleSize = profile[1], dimpleScale = Dimple_Scale);
}
else if(Select_Part_Type == "Connector Double-Sided Rail"){
rail(Length,profile[0], dimplesEnabled = dimplesEnabled, dimpleSize = profile[1], dimpleScale = Dimple_Scale, distanceBetweenDimples = Grid_Size, spin=180){
if(Rounding != "None")
attach(Rounding == "Both Sides" ? [TOP, BOT] : TOP, BOT, overlap=0.01)
roundedEnd(profile[0], dimplesEnabled = dimplesEnabled, dimpleSize = profile[1], dimpleScale = Dimple_Scale);
attach(FRONT, FRONT, overlap=0.01)
rail(Length,profile[0], dimplesEnabled = dimplesEnabled, dimpleSize = profile[1], dimpleScale = Dimple_Scale, distanceBetweenDimples = Grid_Size)
if(Rounding != "None")
attach(Rounding == "Both Sides" ? [TOP, BOT] : TOP, BOT, overlap=0.01)
roundedEnd(profile[0], dimplesEnabled = dimplesEnabled, dimpleSize = profile[1], dimpleScale = Dimple_Scale);
}
}
else if(Select_Part_Type == "Receiver Open-Ended"){
diff(){
cuboid([maxX(profile[0])*2+Receiver_Side_Wall_Thickness*2, maxY(profile[0])+Receiver_Back_Thickness, Length])
attach(BACK, FRONT, inside=true, shiftout=0.01, align=TOP, inset=maxX(profile[0])+Receiver_Top_Wall_Thickness)
rail(Length+0.04, profile[0], dimplesEnabled = dimplesEnabled, dimpleSize = profile[1], dimpleScale = Dimple_Scale, distanceBetweenDimples = Grid_Size){
if(Rounding != "None"){
attach(Rounding == "Both Sides" ? [TOP, BOT] : TOP, BOT, overlap=0.01)
roundedEnd(profile[0], dimplesEnabled = dimplesEnabled, dimpleSize = profile[1], dimpleScale = Dimple_Scale);
}
//onramp
if(onRampEnabled==true) attach(BACK, TOP, inside=true, align=TOP, shiftout=0.02, inset=-maxX(profile[0])+onRampEveryNHoles+onRampOffset) ycopies(n = Length/onRampEveryNHoles+1, spacing = -onRampEveryNHoles, sp=[0,0,0]) cylinder(h = maxY(profile[0])+0.04, r1 = maxX(profile[0])+1.5, r2 = maxX(profile[0]));
}
}
}
else if(Select_Part_Type == "Backer Open-Ended"){
diff(){
cuboid([Width, maxY(profile[0])+Receiver_Back_Thickness, Length])
attach(BACK, FRONT, inside=true, shiftout=0.01, align=TOP, inset=maxX(profile[0])+Receiver_Top_Wall_Thickness)
xcopies(n=floor(Width/Grid_Size), spacing = Grid_Size)
rail(Length+0.04, profile[0], dimplesEnabled = dimplesEnabled, dimpleSize = profile[1], dimpleScale = Dimple_Scale, distanceBetweenDimples = Grid_Size){
if(Rounding != "None"){
attach(Rounding == "Both Sides" ? [TOP, BOT] : TOP, BOT, overlap=0.01)
roundedEnd(profile[0], dimplesEnabled = dimplesEnabled, dimpleSize = profile[1], dimpleScale = Dimple_Scale);
}
//onramp
if(onRampEnabled==true) attach(BACK, TOP, inside=true, align=TOP, shiftout=0.02, inset=-maxX(profile[0])+onRampEveryNHoles+onRampOffset) ycopies(n = Length/onRampEveryNHoles+1, spacing = -onRampEveryNHoles, sp=[0,0,0]) cylinder(h = maxY(profile[0])+0.04, r1 = maxX(profile[0])+1.5, r2 = maxX(profile[0]));
}
}
}
else if(Select_Part_Type == "Backer Passthrough"){
diff(){
cuboid([Width, maxY(profile[0])+Receiver_Back_Thickness, Length])
attach(BACK, FRONT, inside=true, shiftout=0.01)
xcopies(n=floor(Width/Grid_Size), spacing = Grid_Size)
rail(Length+0.04, profile[0], dimplesEnabled = dimplesEnabled, dimpleSize = profile[1], dimpleScale = Dimple_Scale, distanceBetweenDimples = Grid_Size){
if(Rounding != "None")
attach(Rounding == "Both Sides" ? [TOP, BOT] : TOP, BOT, overlap=0.01)
roundedEnd(profile[0], dimplesEnabled = dimplesEnabled, dimpleSize = profile[1], dimpleScale = Dimple_Scale);
//onramp
if(onRampEnabled==true) attach(BACK, TOP, inside=true, align=TOP, shiftout=0.02, inset=-maxX(profile[0])+onRampOffset) ycopies(n = Length/onRampEveryNHoles+1, spacing = -onRampEveryNHoles, sp=[0,0,0]) cylinder(h = maxY(profile[0])+0.04, r1 = maxX(profile[0])+1.5, r2 = maxX(profile[0]));
}
}
}
else if(Select_Part_Type == "Receiver Passthrough"){
diff(){
cuboid([maxX(profile[0])*2+Receiver_Side_Wall_Thickness*2, maxY(profile[0])+Receiver_Back_Thickness, Length])
attach(BACK, FRONT, inside=true, shiftout=0.01) rail(Length+0.04, profile[0], dimplesEnabled = dimplesEnabled, dimpleSize = profile[1], dimpleScale = Dimple_Scale, distanceBetweenDimples = Grid_Size){
if(Rounding != "None")
attach(Rounding == "Both Sides" ? [TOP, BOT] : TOP, BOT, overlap=0.01)
roundedEnd(profile[0], dimplesEnabled = dimplesEnabled, dimpleSize = profile[1], dimpleScale = Dimple_Scale);
//onramp
if(onRampEnabled==true) attach(BACK, TOP, inside=true, align=TOP, shiftout=0.02, inset=-maxX(profile[0])+onRampOffset) ycopies(n = Length/onRampEveryNHoles+1, spacing = -onRampEveryNHoles, sp=[0,0,0]) cylinder(h = maxY(profile[0])+0.04, r1 = maxX(profile[0])+1.5, r2 = maxX(profile[0]));
}
}
}
else if(Select_Part_Type == "Connector Rail Delete Tool"){
//echo(str("Generating: ", Select_Part_Type));
rail(Length, profile[0], onRampEnabled = onRampEnabled, dimpleSize = profile[1], dimplesEnabled = dimplesEnabled, dimpleScale = Dimple_Scale, distanceBetweenDimples = Grid_Size){
if(Rounding != "None")
attach(Rounding == "Both Sides" ? [TOP, BOT] : TOP, BOT, overlap=0.01)
roundedEnd(profile[0], dimplesEnabled = dimplesEnabled, dimpleSize = profile[1], dimpleScale = Dimple_Scale);
if(onRampEnabled==true) attach(BACK, TOP, inside=true, align=TOP, shiftout=0.02, inset=-maxX(profile[0])+onRampOffset) ycopies(n = Length/onRampEveryNHoles+1, spacing = -onRampEveryNHoles, sp=[0,0,0]) cylinder(h = maxY(profile[0])+0.04, r1 = maxX(profile[0])+1.5, r2 = maxX(profile[0]));
}
}
}
module roundedEnd(profile, dimplesEnabled = true, dimpleSize = 1, dimpleScale = 1, anchor=CENTER, spin=0, orient=UP){
attachable(anchor, spin, orient, size=[maxX(profile)*2,maxY(profile),maxX(profile)]){
//align to anchors
down(maxX(profile)/2) back(maxY(profile)/2)
top_half()
rotate(a = [90,0,0])
difference(){
//rail
rotate_extrude($fn=25)
polygon(points = profile);
//dimples
if(dimplesEnabled == true) {
down(0.01) cylinder(h = dimpleSize*dimpleScale, r1 = dimpleSize*dimpleScale, r2 = 0, $fn = 25);
}
}
children();
}
}
module rail(length, profile, dimplesEnabled = true, dimpleSize = 1, dimpleScale = 1, distanceBetweenDimples = 25, onRampEnabled = false, onRampDistanceBetween = 50, anchor=CENTER, spin=0, orient=UP){
attachable(anchor, spin, orient, size=[maxX(profile)*2,maxY(profile),length]){
up(length/2) back(maxY(profile)/2)
difference(){
//rail
rotate(a = [180,0,0])
linear_extrude(height = length)
union(){
polygon(points = profile);
mirror([1,0,0])
polygon(points = profile);
}
//dimples
if(dimplesEnabled)
zcopies(n = ceil(length/distanceBetweenDimples)+1, spacing = distanceBetweenDimples, sp=[0,0,-length+length%distanceBetweenDimples])
back(0.01)cylinder(h = dimpleSize*dimpleScale, r1 = dimpleSize*dimpleScale, r2 = 0, $fn = 25, orient=FWD);
}
children();
}
}
//calculate the max x and y points. Useful in calculating size of an object when the path are all positive variables originating from [0,0]
function maxX(path) = max([for (p = path) p[0]]);
function maxY(path) = max([for (p = path) p[1]]);
//this function takes the measurements of a multiconnect-style dovetail and converts them to profile coordinates.
//When generating the male connector, set offsetMM to zero. Otherwise standard is 0.15 offset for delete tool
function dimensionsToCoords(radius, depth1, depth2, depth3, offsetMM) = [
[0,0],
[radius+offsetMM, 0],
[radius+offsetMM,offsetMM == 0 ? depth1 : depth1+sin(45)*offsetMM*2],
[radius-depth2+offsetMM, offsetMM == 0 ? depth2+depth1 : depth2+depth1+sin(45)*offsetMM*2],
[radius-depth2+offsetMM, depth2+depth1+depth3+offsetMM],
[0,depth2+depth1+depth3+offsetMM]
];
//
//END Multiconnect Modules and Functions
//