This is laid in against a need I hope never occurs:

It’s intended to clamp around one of the Dripworks mainline pipes carrying water from the pressure regulator to the driplines in the raised beds, should an errant shovel or fork find the pipe.
It descends from a long line of soaker hose clamps, with a 25 mm ID allowing for a silicone tape wrap as a water barrier.
The solid model has no surprises:

The OpenSCAD source code as a GitHub Gist:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Dripworks 3/4 inch mainline clamp | |
// Ed Nisley KE4ZNU 2021-06 | |
Layout = "Build"; // [Hose,Block,Show,Build] | |
HoseOD = 25.0; | |
TestFit = false; // true to build test fit slice from center | |
//- Extrusion parameters must match reality! | |
/* [Hidden] */ | |
ThreadThick = 0.25; | |
ThreadWidth = 0.40; | |
HoleWindage = 0.2; | |
Protrusion = 0.1; // make holes end cleanly | |
inch = 25.4; | |
function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit); | |
ID = 0; | |
OD = 1; | |
LENGTH = 2; | |
//---------- | |
// Dimensions | |
// Hose lies along X axis | |
Hose = [200,HoseOD,HoseOD]; // X = longer than anything else | |
NumScrews = 2; // screws along each side of cable | |
WallThick = 3.0; // Thinnest printed wall | |
PlateThick = 1.5; // Stiffening plate thickness | |
// 8-32 stainless screws | |
Screw = [4.1,8.0,50.0]; // OD = head LENGTH = thread length | |
Washer = [4.4,9.5,1.0]; | |
Nut = [4.1,9.7,3.3]; | |
Block = [30.0,Hose.y + 2*Washer[OD],HoseOD + 2*WallThick]; // overall splice block size | |
echo(str("Block: ",Block)); | |
ScrewMinLength = Block.z + 2*PlateThick + 2*Washer.z + Nut.z; // minimum screw length | |
echo(str("Screw min length: ",ScrewMinLength)); | |
Kerf = 1.0; // cut through middle to apply compression | |
CornerRadius = Washer[OD]/2; | |
ScrewOC = [(Block.x - 2*CornerRadius) / (NumScrews - 1), | |
Block.y - 2*CornerRadius, | |
2*Block.z // ensure complete holes | |
]; | |
echo(str("Screw OC: x=",ScrewOC.x," y=",ScrewOC.y)); | |
//---------------------- | |
// Useful routines | |
module PolyCyl(Dia,Height,ForceSides=0) { // based on nophead's polyholes | |
Sides = (ForceSides != 0) ? ForceSides : (ceil(Dia) + 2); | |
FixDia = Dia / cos(180/Sides); | |
cylinder(d=(FixDia + HoleWindage),h=Height,$fn=Sides); | |
} | |
// Hose shape | |
// This includes magic numbers measured from reality | |
module HoseProfile() { | |
NumSides = 12*4; | |
rotate([0,-90,0]) | |
translate([0,0,-Hose.x/2]) | |
resize([Hose.z,Hose.y,0]) | |
cylinder(d=Hose.z,h=Hose.x,$fn=NumSides); | |
} | |
// Outside shape of splice Block | |
// Z centered on hose rim circles, not overall thickness through center ridge | |
module SpliceBlock() { | |
difference() { | |
hull() | |
for (i=[-1,1], j=[-1,1]) // rounded block | |
translate([i*(Block.x/2 - CornerRadius),j*(Block.y/2 - CornerRadius),-Block.z/2]) | |
cylinder(r=CornerRadius,h=Block.z,$fn=4*8); | |
for (i = [0:NumScrews - 1], j=[-1,1]) // screw holes | |
translate([-(Block.x/2 - CornerRadius) + i*ScrewOC.x, | |
j*ScrewOC.y/2, | |
-(Block.z/2 + Protrusion)]) | |
PolyCyl(Screw[ID],Block.z + 2*Protrusion,6); | |
cube([2*Block.x,2*Block.y,Kerf],center=true); // slice through center | |
} | |
} | |
// Splice block less hose | |
module ShapedBlock() { | |
difference() { | |
SpliceBlock(); | |
HoseProfile(); | |
} | |
} | |
//---------- | |
// Build them | |
if (Layout == "Hose") | |
HoseProfile(); | |
if (Layout == "Block") | |
SpliceBlock(); | |
if (Layout == "Show") { | |
difference() { | |
SpliceBlock(); | |
HoseProfile(); | |
} | |
color("Green",0.25) | |
HoseProfile(); | |
} | |
if (Layout == "Build") { | |
SliceOffset = TestFit && !(NumScrews % 2) ? ScrewOC.x/2 : 0; | |
intersection() { | |
translate([SliceOffset,0,Block.z/4]) | |
if (TestFit) | |
cube([ScrewOC.x/2,4*Block.y,Block.z/2],center=true); | |
else | |
cube([4*Block.x,4*Block.y,Block.z/2],center=true); | |
union() { | |
translate([0,0.6*Block.y,Block.z/2]) | |
ShapedBlock(); | |
translate([0,-0.6*Block.y,Block.z/2]) | |
rotate([0,180,0]) | |
ShapedBlock(); | |
} | |
} | |
} |