Ever bought a vintage pump with a BS336 fire hose fitting and not had a mating half? Not a very common problem I know, but in case it's useful to anyone here is an openscad implimentation of a BS336 suction fitting. Note it relies on some libraries here. The capital letters in the comments refer to the measurements specified in the standard.


use <RCS_SCAD_Modules.scad>
use <ShortCuts.scad>
use <Spiral_Extrude.scad>
use <threads.scad>



backing = 1;
maleR = 1.85;
femaleR = 2.39;
radOffset = 1.07;
pitch = 8.466;

maleCouplerMajorD = 91.8;

maleCouplerMinorD =  maleCouplerMajorD - 2*(maleR+femaleR+radOffset);
echo("male minor d =",  maleCouplerMinorD);

femaleCouplerMinorD = 82.8;

femaleCouplerMajorD = femaleCouplerMinorD + 2*(maleR+femaleR+radOffset);
echo("female major d =", femaleCouplerMajorD);


$fn=50;



tailMatingOD = 68.2; // L
tailMatingL = 6.35;
tailRimD = 92.0; //K
tailRimL = 8;
tailNutD = 77.8; //E
tailNutL = 27;
tailTransitionL = 4;
tailNarrowD = 71.4; // F
tailWideD = 77.8; //E
tailSlopeL = 13;
tailT = 4 ; //t
tailNarrow1L = 38 ; // G - 13 - 13 - H
tailNarrow2L = 25; //H

tailLength = 6.35+8+27+89;
tailID = tailNarrowD - 2*tailT;

nutLength = 57;
nutThreadedLength = nutLength - 31;
nutThreads = nutThreadedLength/pitch;
nutLowerOD = 110; //N
nutLowerL = 15;
nutLugOD = 171; //P
nutLugD = 19; //R
nutMidOD = nutLugOD-2*22;
nutMidL = nutLugD +6;
nutTopOD = 114.3; //S1
nutTopL = 17;
nutID = 93.7;//K1
nutFinethreadPitch = 8; //TPI
nutFinethreadOD = 3.90; //inches
nutFinethreadL = 17;

//nutLength = nutLowerL+nutMidL+nutTopL;

lockingRingL = 22;
lockingRingOD = 114.3; //S
lockingRingID = 80.2; //Q
lockingRingUndercutL = 3;
lockingRingThreadL = 16 - lockingRingUndercutL;
lockingRingChampherL = 3;
lockingRingNotchW = 10;
lockingRingNotchH = 8;

lockingRingTopL = lockingRingL - lockingRingThreadL - lockingRingUndercutL;

washerID = 68.2; //J1
washerOD = 90; //J
washerT = 6;

section = false;



// Tail

Tz(nutThreadedLength)
difference() {
    union() {
        
        cylinder(d=tailMatingOD, h=tailMatingL+0.1);
        
        Tz(tailMatingL)
        cylinder(d=tailRimD, h=tailRimL);
        
        Tz(tailMatingL+tailRimL-0.1)
        cylinder(d=tailNutD, h=tailNutL+0.1);
        
        Tz(tailMatingL+tailRimL+tailNutL)
        cylinder(d1=tailNutD, d2=tailNarrowD, h=tailTransitionL);
        
        Tz(tailMatingL+tailRimL+tailNutL)
        cylinder(d=tailNarrowD, h=tailNarrow1L+2*tailSlopeL+tailNarrow2L);
        
        Tz(tailMatingL+tailRimL+tailNutL+tailNarrow1L)
        cylinder(d1=tailWideD, d2=tailNarrowD, h=tailSlopeL);

        Tz(tailMatingL+tailRimL+tailNutL+tailNarrow1L+tailSlopeL+tailNarrow2L)
        cylinder(d1=tailWideD, d2=tailNarrowD, h=tailSlopeL);        
        
    }
    
    Tz(-1)
    cylinder(d=tailID, h=tailLength+2);
    
    if (section) {
        Tz(-1)
        cube(200);
    }
}

// Nut
difference() {
    union() {
        
        //thread
        Tz(-pitch)
        extrude_spiral(StartRadius=femaleCouplerMajorD/2, Angle=360*(nutThreads+1), RPitch=0, ZPitch=pitch, StepsPerRev=60)
        female_suction_thread_2D($fn=20);
        
        // outside profile
        ring(D=nutLowerOD, d=femaleCouplerMajorD+backing, h=nutLowerL+0.1, center=false, $fn=100);
        
        Tz(nutLowerL)
        ring(D=nutMidOD, d=femaleCouplerMajorD+backing, h=nutMidL, center=false, $fn=100);
        
        Tz(nutLowerL+nutMidL-0.1)
        ring(D=nutTopOD, d=femaleCouplerMajorD+backing, h=nutTopL+0.1, center=false, $fn=100);
        
        // lugs
        
        for (i = [0:3]) {
            
            Rz(i*90)
            Tz(nutLowerL+nutMidL/2)
            Ry(90)
            Tz(nutMidOD/2-3)
            cylinder(d=nutLugD, h=(nutLugOD-nutMidOD)/2+3, , $fn=50);
            
        }
    }
    
    // trim away bototm of thread
    Tz(-pitch)
    cylinder(d=2*femaleCouplerMajorD, h=2*pitch, center=true);
    
    // Inner D before fine thread
    Tz(nutThreadedLength)
    cylinder(d=nutID, h=nutLength, $fn=60);
    
    // fine thread
    
    Tz(nutLength-nutFinethreadL)
    //render()
    english_thread(diameter=nutFinethreadOD, threads_per_inch=nutFinethreadPitch, length=(nutFinethreadL+1)/25.4, internal=true, test=false
    
    
    );
    
    
    if (section) {
        Tz(-1)
        cube(200);
    }
}


// Locking ring
Tz(nutLength-nutFinethreadL+0.5)
difference() {
    union() {
        
        english_thread(diameter=nutFinethreadOD, threads_per_inch=nutFinethreadPitch, length=lockingRingThreadL/25.4, internal=false, test=false, leadin=3);
        
        Tz(lockingRingThreadL-0.1)
        cylinder(d=25.4*nutFinethreadOD-(25.4/nutFinethreadPitch), h=lockingRingUndercutL+0.2);
        
        Tz(lockingRingThreadL+lockingRingUndercutL)
        cylinder(d=lockingRingOD, h=lockingRingTopL);
        
    }
    
    cylinder(d=lockingRingID, h=100, center=true);
    
    // notches for hook spanner
    for (i = [0:3]) {
        
        Tz(lockingRingThreadL+lockingRingUndercutL+lockingRingTopL/2)
        Rz(i*90)
        Tx(lockingRingOD/2)
        cube([2*lockingRingNotchH,lockingRingNotchW,lockingRingTopL+1], center=true);
        
    }
    
    //chamfer
    Tz(lockingRingL-lockingRingChampherL)
    cylinder(d1=0, d2=2*lockingRingID, h=lockingRingID, center=true);
    
    
    if (section) {
        Tz(-1)
        cube(200);
    }
}


// Washer
Tz(nutThreadedLength)
ring(D=washerOD, d=washerID, h=washerT, center=false, $fn=100);


// Thread tests
*
extrude_spiral(StartRadius=maleCouplerMinorD/2, Angle=720, RPitch=0, ZPitch=pitch, StepsPerRev=72)
male_suction_thread_2D();
*
rotate_extrude(angle=1)
Ty(pitch/2)
Tx(femaleCouplerMajorD/2)
female_suction_thread_2D();



// Modules = threads

module male_suction_thread_2D()
Tx(-backing)
union() {

    square([backing,pitch]);

    Ty(pitch/2)
    Tx(backing+femaleR+radOffset)
    circle(r=maleR);
    
    Ty(pitch/2 - maleR)
    square([backing+femaleR+radOffset,2*maleR]);
    
    difference() {
        
        square([backing+femaleR,2*femaleR]);
        
        Tx(backing+femaleR)
        circle(r=femaleR);
        
    }
    
    Ty(pitch-2*femaleR)
    difference() {
        
        square([backing+femaleR,2*femaleR]);
        Ty(2*femaleR)
        Tx(backing+femaleR)
        circle(r=femaleR);
        
    }
    
}



module female_suction_thread_2D()
Tx(backing)
mirror([1,0,0])
union() {
    
    square([backing,pitch]);

    Ty(pitch/2)
    Tx(backing+femaleR+radOffset)
    circle(r=maleR);
    
    Ty(pitch/2 - maleR)
    square([backing+femaleR+radOffset,2*maleR]);
    
    difference() {
        
        square([backing+femaleR,2*femaleR]);
        
        Tx(backing+femaleR)
        circle(r=femaleR);
        
    }
    
    Ty(pitch-2*femaleR)
    difference() {
        
        square([backing+femaleR,2*femaleR]);
        Ty(2*femaleR)
        Tx(backing+femaleR)
        circle(r=femaleR);
        
    }
    
}

Giving this result (with section set to true):

OpenSCAD screenshot

And this is what it looks like 3D printed in Nylon (right) after attempt 1 in PLA failed due to creeping in the hot sun (left).

Failed PLA print Dumper on trailer