Improved Lipstick and Lip Balm Holder With Text

For reasons that aren’t relevant here, Mary asked me to make four sets of improved lipstick / lip balm / sunscreen holders with five smaller tubes plus the central one and an inscription on the bottom. I ran off one with the last of the cyan PETG and the other three in natural PETG:

Improved Lipstick Holder - on platform
Improved Lipstick Holder – on platform

I embossed the text into the bottom three layers. The tiny spots of detached infill for lowercase letters like a didn’t adhere to the platform, mostly because the retraction settings that work well for larger areas don’t push enough plastic out to bond with the platform before retracting and moving away.

The bridging layer over the text shows Slic3r doing the best it can (clicky for more far more dots). Laying a uniform patch over all the letters in one shot would work better, but I don’t know how you’d define an algorithm that specifies when such a situation occurs:

Lip Balm Holder - text bridge layer - Slic3r preview
Lip Balm Holder – text bridge layer – Slic3r preview

The solid infill layer directly over the Hilbert Curve bottom layer came out grossly severely excessively overstuffed, to the extent that the accumulation reduced the flow of molten plastic and caused the filament drive to strip:

Overfilled layer 2
Overfilled layer 2

Previewing the G-Code show nothing out of the ordinary and, after considerable flailing around, I finally set Slic3r to begin the 3D Honeycomb infill directly atop the Hilbert Curve bottom layer. That provided enough open space to complete the mission, but more debugging was in order.

The OpenSCAD source code as a GitHub gist:

// Lipstick and Balm Tube Holder
// Ed Nisley KE4ZNU - February 2016
//- Extrusion parameters - must match reality!
ThreadThick = 0.25;
ThreadWidth = 0.40;
function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit);
Protrusion = 0.1;
HoleWindage = 0.2;
//------
// Dimensions
RawDia = [27,18,16,18,16,18]; // actual tube diameters in desired order, center = largest first
NumTubes = len(RawDia);
Clearance = 2.0;
TubeDia = [for (i=[0:NumTubes-1]) (RawDia[i] + Clearance)]; // actual tube diameters
TubeRad = TubeDia / 2;
echo(str("NumTubes: ",NumTubes));
Wall = 2.0;
BaseThick = 2.0;
BaseFactor = 2.0;
NumSides = 12*4;
// per-tube info, first element forced to 0 to make entries match RawDia vector indexes
Radius = [0, for (i=[1:NumTubes-1]) (TubeRad[0] + TubeRad[i] + Wall)]; // Tube[i] distance to center point
echo(str("Radius: ",Radius));
CtrToCtr = [0, for (i=[1:NumTubes-2]) (TubeRad[i] + TubeRad[i+1] + Wall)]; // Tube[i] distance to Tube[i+1]
echo(str("CtrToCtr: ",CtrToCtr));
Angle = [0, for (i=[1:NumTubes-2]) acos((pow(Radius[i],2) + pow(Radius[i+1],2) - pow(CtrToCtr[i],2)) / (2 * Radius[i] * Radius[i+1]))];
echo(str("Angle: ",Angle));
TotalAngle = sumv(Angle,len(Angle)-1);
echo(str("TotalAngle: ",TotalAngle));
//----------------------
// Useful routines
// vector sum cribbed from doc
function sumv(v,i,s=0) = (i==s ? v[i] : v[i] + sumv(v,i-1,s));
//----------------------
//- Build it
difference() {
union() {
for (i=[0:NumTubes-1])
rotate(90 - TotalAngle/2 + sumv(Angle, (i>0) ? (i-1) : 0))
translate([Radius[i],0,0]) {
resize([0,0,2*BaseThick]) // bases
difference() {
sphere(r=BaseFactor*TubeRad[i],$fn=NumSides);
translate([0,0,-BaseFactor*TubeDia[i]])
cube(2*BaseFactor*TubeDia[i],center=true);
}
difference() { // tubes
cylinder(r=TubeRad[i] + Wall,h=1.5*TubeDia[i] + BaseThick,$fn=NumSides);
cylinder(d=TubeDia[i],h=1.5*TubeDia[i] + BaseThick + Protrusion,$fn=NumSides);
}
}
for (i=[1:NumTubes-2]) // gap plugs
rotate(90 - TotalAngle/2 + sumv(Angle,i-1) + (Angle[i])/2)
translate([(TubeRad[0] + Wall),0,0])
cylinder(r=2*Wall,h=1.5*min(TubeDia[i],TubeDia[i+1]) + BaseThick,$fn=3);
}
translate([0,0,-Protrusion]) // text
mirror([1,0,0])
linear_extrude(height=3*ThreadThick + Protrusion) {
translate([0,25,0])
text(text="Linda",size=7,spacing=1.05,font="Arial:style=Bold Italic",halign="center");
translate([0,15,0])
text(text="FDQ ExComm",size=5,spacing=1.05,font="Arial:style=Regular",halign="center");
translate([0,7,0])
text(text="2014 - 2016",size=5,spacing=1.05,font="Arial:style=Regular",halign="center");
translate([0,-3,0])
text(text="Thank you!",size=6,spacing=1.05,font="Arial:style=Regular",halign="center");
translate([0,-15,0])
text(text="Mary Nisley",size=7,spacing=1.10,font="ITC Zapf Chancery:style=Medium Italic",halign="center");
}
}