Last active
June 13, 2026 19:34
-
-
Save JamesNewton/22181ea697c9424ecfebe3d8037cd884 to your computer and use it in GitHub Desktop.
Well Drilling
This file contains hidden or 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
| /* | |
| 1/2 inch treaded rod is cheap and easy to grind teeth into. | |
| It can be joined, and while the sections buldge out, they can also have teeth ground into them | |
| and so can cut their way down. | |
| The problem is getting the muck out. A Ball valve will clog, a flap valve need to be bigger than | |
| the ID of the pipe. You probably want a duckbill valve. e.g. | |
| https://www.rubbervalve.com/duckbill-valve/? | |
| But they aren't available in a size that fits in the common 1/2 threaded steel pipe. So we can | |
| print one in TPU. | |
| This is an https://openjscad.xyz program for a parametric model for a duckbill valve. You can | |
| export the STL and then print it. | |
| */ | |
| const { cylinder, cuboid } = require('@jscad/modeling').primitives; | |
| const { translate } = require('@jscad/modeling').transforms; | |
| const { subtract, union } = require('@jscad/modeling').booleans; | |
| const { hull } = require('@jscad/modeling').hulls; | |
| const getParameterDefinitions = () => { | |
| return [ | |
| // Flange (The wide "lip" that screws into the coupling) | |
| { name: 'flangeCoreOD', type: 'float', initial: 17, caption: 'Flange Core OD (mm)' }, | |
| { name: 'flangeRibOD', type: 'float', initial: 18.0, caption: 'Flange Rib OD (mm)' }, | |
| { name: 'flangeHeight', type: 'float', initial: 9.0, caption: 'Flange Total Height (mm)' }, | |
| { name: 'flangeRibCount', type: 'int', initial: 4, caption: 'Flange Rib Count' }, | |
| // Base Tube (The smooth shaft) | |
| { name: 'baseOD', type: 'float', initial: 16.0, caption: 'Base Tube OD (mm)' }, | |
| { name: 'baseID', type: 'float', initial: 14.0, caption: 'Base Tube ID (mm)' }, | |
| { name: 'baseHeight', type: 'float', initial: 10.0, caption: 'Base Tube Height (mm)' }, | |
| // Duckbill Lips | |
| { name: 'billHeight', type: 'float', initial: 17.0, caption: 'Duckbill Height (mm)' }, | |
| { name: 'lipThickness', type: 'float', initial: 0.8, caption: 'Lip Wall Thickness (mm)' }, | |
| { name: 'slitWidth', type: 'float', initial: 0.2, caption: 'Slit Width (mm)' }, | |
| // Resolution | |
| { name: 'segments', type: 'int', initial: 64, caption: 'Resolution' } | |
| ]; | |
| }; | |
| const main = (params) => { | |
| const { | |
| flangeCoreOD, flangeRibOD, flangeHeight, flangeRibCount, | |
| baseOD, baseID, baseHeight, | |
| billHeight, lipThickness, slitWidth, segments | |
| } = params; | |
| // 1. Gasket / Flange Section (Now with a narrower core and locking ribs) | |
| const flangeCore = cylinder({ radius: flangeCoreOD / 2, height: flangeHeight, segments }); | |
| const flangeCorePos = translate([0, 0, flangeHeight / 2], flangeCore); | |
| let flangeRibsArray = []; | |
| if (flangeRibCount > 0) { | |
| const fSpacing = flangeHeight / (flangeRibCount - 0.62); | |
| for (let i = 0; i < flangeRibCount; i++) { | |
| // 1mm thick rings acting as threads | |
| const fRib = cylinder({ radius: flangeRibOD / 2, height: 1.0, segments }); | |
| const fRibPos = translate([0, 0, fSpacing * i + 0.5], fRib); | |
| flangeRibsArray.push(fRibPos); | |
| } | |
| } | |
| const allFlangeRibs = flangeRibsArray.length > 0 ? union(flangeRibsArray) : null; | |
| const ribbedFlange = allFlangeRibs ? union(flangeCorePos, allFlangeRibs) : flangeCorePos; | |
| // 2. Base Tube Section (The smooth core) | |
| const baseTube = cylinder({ radius: baseOD / 2, height: baseHeight, segments }); | |
| const baseTubePos = translate([0, 0, baseHeight / 2 + flangeHeight], baseTube); | |
| // 3. Outer Duckbill (Hull from cylinder to flat line) | |
| const billBaseOuter = cylinder({ radius: baseOD / 2, height: 0.1, segments }); | |
| const billBaseOuterPos = translate([0, 0, baseHeight + flangeHeight], billBaseOuter); | |
| const billTipOuter = cuboid({ size: [baseOD * 0.9, lipThickness * 2 + slitWidth, 0.1] }); | |
| const billTipOuterPos = translate([0, 0, baseHeight + flangeHeight + billHeight], billTipOuter); | |
| const outerBill = hull(billBaseOuterPos, billTipOuterPos); | |
| // Combine entire outer body | |
| const outerBody = union(ribbedFlange, baseTubePos, outerBill); | |
| // 4. Inner Hollow Section (to subtract) | |
| // Ensure the bore cuts cleanly through the bottom by extending it down slightly (-0.05) | |
| const innerTube = cylinder({ radius: baseID / 2, height: baseHeight + flangeHeight + 0.1, segments }); | |
| const innerTubePos = translate([0, 0, (baseHeight + flangeHeight) / 2 - 0.05], innerTube); | |
| const billBaseInner = cylinder({ radius: baseID / 2, height: 0.1, segments }); | |
| const billBaseInnerPos = translate([0, 0, baseHeight + flangeHeight], billBaseInner); | |
| const billTipInner = cuboid({ size: [baseID * 1, slitWidth, 0.2] }); | |
| const billTipInnerPos = translate([0, 0, baseHeight + flangeHeight + billHeight], billTipInner); | |
| const innerBill = hull(billBaseInnerPos, billTipInnerPos); | |
| // Combine inner negative volume | |
| const innerBody = union(innerTubePos, innerBill); | |
| // 5. Subtract inside from outside to create the shell | |
| return subtract(outerBody, innerBody); | |
| }; | |
| module.exports = { main, getParameterDefinitions }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment