Watering can
Note that this model is inspired by Robert Bronwasser's watering can. The original implementation comes from our community. You can see step by step explanation on how to build it here
And here is what the code looks like.
const { makePlane, makeCylinder, draw, drawCircle } = replicad;
const defaultParams = {};
const main = () => {
// Building the body
const profile = draw()
.hLine(20)
.line(10, 5)
.vLine(3)
.lineTo([8, 100])
.hLine(-8)
.close();
const body = profile.sketchOnPlane("XZ").revolve([0, 0, 1]);
// Building the filler
const topPlane = makePlane().pivot(-20, "Y").translate([-35, 0, 135]);
const topCircle = drawCircle(12).sketchOnPlane(topPlane);
const middleCircle = drawCircle(8).sketchOnPlane("XY", 100);
const bottomPlane = makePlane().pivot(20, "Y").translateZ(80);
const bottomCircle = drawCircle(9).sketchOnPlane(bottomPlane);
const filler = topCircle.loftWith([middleCircle, bottomCircle], {
ruled: false,
});
// Building the spout
const spout = makeCylinder(5, 70)
.translateZ(100)
.rotate(45, [0, 0, 100], [0, 1, 0]);
let wateringCan = body
.fuse(filler)
.fillet(30, (e) => e.inPlane("XY", 100))
.fuse(spout)
.fillet(10, (e) => e.inBox([20, 20, 100], [-20, -20, 120]));
const spoutOpening = [
Math.cos((45 * Math.PI) / 180) * 70,
0,
100 + Math.sin((45 * Math.PI) / 180) * 70,
];
wateringCan = wateringCan.shell(-1, (face) =>
face.either([
(f) => f.containsPoint(spoutOpening),
(f) => f.inPlane(topPlane),
])
);
return {
shape: wateringCan,
name: "Watering Can",
};
};