Soap dish v3 (radial lines)
by Mach3 ·
Radial lines. Optional water collector tray. This is an assembly, so switch "part" to download separate .stl models for dish and tray parts.
Interactive Preview & Customizer
3D STL viewer with browser-based OpenSCAD rendering on parameter changes.
Which part to preview or export
Vertical gap between tray and dish in assembly preview (mm)
Outer frame width (mm)
Outer frame height (mm)
Total dish thickness (mm)
Border wall thickness (mm)
Outer corner radius (mm)
Distance between radial ribs (mm)
Thickness of each radial rib (mm)
Ripple center X offset from model center (mm)
Ripple center Y offset from model center (mm)
Radius of spherical scoop cutout (mm)
Depth of scoop from top surface (mm)
Clearance around dish footprint inside tray (mm)
Tray wall and floor thickness (mm)
Total tray height (mm)
Curve smoothness for rounded geometry
Prompt
lets replace hexes with waved lines
OpenSCAD Code
// Offset Radial Soap Dish + Optional Drip Tray
// Concentric arcs anchored to walls for printability
/* [Output] */
// Which part to preview or export
part = "assembly"; // [dish,tray,assembly]
// Vertical gap between tray and dish in assembly preview (mm)
assembly_gap = 1.0; // [0:0.5:8]
/* [Frame] */
// Outer frame width (mm)
frame_width = 135; // [80:1:220]
// Outer frame height (mm)
frame_height = 135; // [80:1:220]
// Total dish thickness (mm)
frame_depth = 24; // [8:0.5:60]
// Border wall thickness (mm)
frame_border = 2.0; // [1:0.1:8]
// Outer corner radius (mm)
corner_radius = 35; // [8:0.5:70]
/* [Ribs] */
// Distance between radial ribs (mm)
ring_spacing = 11; // [4:0.5:24]
// Thickness of each radial rib (mm)
ring_thickness = 2.5; // [0.6:0.1:8]
// Ripple center X offset from model center (mm)
ripple_offset_x = 120; // [0:1:260]
// Ripple center Y offset from model center (mm)
ripple_offset_y = 120; // [0:1:260]
/* [Bowl] */
// Radius of spherical scoop cutout (mm)
dish_radius = 220; // [120:1:420]
// Depth of scoop from top surface (mm)
dish_depth = 16; // [4:0.5:36]
/* [Tray] */
// Clearance around dish footprint inside tray (mm)
tray_tolerance = 1.0; // [0:0.1:3]
// Tray wall and floor thickness (mm)
tray_wall_thickness = 2.0; // [0.8:0.1:8]
// Total tray height (mm)
tray_height = 8; // [2:0.5:30]
/* [Quality] */
// Curve smoothness for rounded geometry
$fn = 100; // [48:1:180]
// --- Render selection ---
if (part == "dish") {
soap_dish_body();
} else if (part == "tray") {
drip_tray();
} else if (part == "assembly") {
drip_tray();
translate([0, 0, tray_height + assembly_gap]) soap_dish_body();
}
// --- Modules ---
module soap_dish_body() {
// Position sphere so its bottom reaches the desired depth
sphere_z_offset = (frame_depth - dish_depth) + dish_radius;
// Calculate max distance to cover the opposite corner
max_dist = sqrt(
pow(ripple_offset_x + frame_width / 2, 2)
+ pow(ripple_offset_y + frame_height / 2, 2)
);
difference() {
union() {
// 1. Outer border frame
difference() {
rounded_square(frame_width, frame_height, frame_depth, corner_radius);
// Interior cutout
translate([0, 0, -1])
rounded_square(
frame_width - frame_border * 2,
frame_height - frame_border * 2,
frame_depth + 2,
corner_radius - frame_border
);
}
// 2. Anchored arc fill
intersection() {
// Keep arcs inside the frame boundary
rounded_square(
frame_width - frame_border,
frame_height - frame_border,
frame_depth,
corner_radius - frame_border / 2
);
// Generate rings from the offset center
translate([ripple_offset_x, ripple_offset_y, 0])
concentric_rings(max_dist, ring_spacing, ring_thickness, frame_depth);
}
}
// 3. Concave scoop
translate([0, 0, sphere_z_offset])
sphere(r = dish_radius);
}
}
module drip_tray() {
// Fit tray to the soap dish outer footprint
tray_inner_w = frame_width + (tray_tolerance * 2);
tray_inner_h = frame_height + (tray_tolerance * 2);
tray_inner_r = corner_radius + tray_tolerance;
tray_outer_w = tray_inner_w + (tray_wall_thickness * 2);
tray_outer_h = tray_inner_h + (tray_wall_thickness * 2);
tray_outer_r = tray_inner_r + tray_wall_thickness;
difference() {
// Outer tray body
rounded_square(tray_outer_w, tray_outer_h, tray_height, tray_outer_r);
// Inner cavity; shifted up to keep floor thickness
translate([0, 0, tray_wall_thickness])
rounded_square(tray_inner_w, tray_inner_h, tray_height, tray_inner_r);
}
}
module concentric_rings(max_r, spacing, thick, height) {
// Start from 0 to max_r, though only arcs hitting the frame will be rendered
for (r = [0 : spacing : max_r]) {
difference() {
cylinder(h = height, r = r + thick / 2);
translate([0, 0, -0.5])
cylinder(h = height + 1, r = r - thick / 2);
}
}
}
module rounded_square(w, h, z, r) {
translate([-w / 2 + r, -h / 2 + r, 0])
hull() {
cylinder(h = z, r = r);
translate([w - 2 * r, 0, 0]) cylinder(h = z, r = r);
translate([0, h - 2 * r, 0]) cylinder(h = z, r = r);
translate([w - 2 * r, h - 2 * r, 0]) cylinder(h = z, r = r);
}
}