diff vs i2: +89/-90
// OpenSCAD Mug with Handle
// Global rendering quality (higher value = smoother curves)
$fn = 64;
// Mug body parameters
mug_outer_radius = 80 / 2; // 40mm
mug_inner_radius = 70 / 2; // 35mm
mug_height = 90;
mug_bottom_thickness = 6;
// Handle parameters
handle_thickness = 10; // Thickness of the handle material
handle_inner_width = 25; // Internal width of the finger hole (X direction)
handle_inner_height = 30; // Internal height of the finger hole (Z direction)
// Overlap for robust union between handle and mug body, and between handle components
// A small positive value ensures parts slightly penetrate each other,
// which helps OpenSCAD create a manifold solid and avoids Z-fighting artifacts.
handle_overlap_epsilon = 0.5; // Example: 0.5mm overlap
- // Calculate handle positioning
- handle_z_center = mug_height / 2; // Center of the handle vertically on the mug
- handle_y_center = 0; // Center of the handle horizontally (aligned with mug's Y axis)
-
module mug_body() {
difference() {
// Outer cylinder of the mug
cylinder(h = mug_height, r = mug_outer_radius);
// Inner hollow part
// Lifted by mug_bottom_thickness to create the solid bottom
// Slightly increased height to avoid Z-fighting artifacts on the top surface
translate([0, 0, mug_bottom_thickness])
cylinder(h = mug_height - mug_bottom_thickness + handle_overlap_epsilon, r = mug_inner_radius);
}
}
module mug_handle() {
- // Define key X-coordinates for the handle construction for clarity and precision.
- // The X-coordinate where the handle's outermost surface (if no overlap) would meet the mug.
- x_mug_outer_surface = mug_outer_radius;
+ // Calculate dimensions for the D-shape handle
+ // Total height of the handle from top edge to bottom edge
+ handle_total_height = handle_inner_height + 2 * handle_thickness;
+ // Outer radius of the D-arc (half of total height)
+ outer_d_arc_radius = handle_total_height / 2;
+ // Inner radius of the D-arc (half of inner height)
+ inner_d_arc_radius = handle_inner_height / 2;
- // The X-coordinate where the handle's vertical bar starts, embedded into the mug.
- x_handle_start_embedded = x_mug_outer_surface - handle_overlap_epsilon;
+ // Position the handle:
+ // Translate its "attachment point" (the X-coordinate where it meets the mug)
+ // to mug_outer_radius. We subtract handle_overlap_epsilon to embed it slightly.
+ // Its Y-center is 0 (aligned with mug's Y axis).
+ // Its Z-center is mug_height / 2 (aligned with mug's height center).
+ translate([
+ mug_outer_radius - handle_overlap_epsilon, // X: start slightly inside mug
+ 0, // Y: centered
+ mug_height / 2 // Z: centered
+ ]) {
+ // Build the handle using difference between its outer solid shape and its inner cut-out shape.
+ difference() {
+ // 1. Outer solid handle shape
+ union() {
+ // Rectangular part of the outer handle (from mug to the start of the arc)
+ // In its local coordinate system:
+ // X starts at -handle_overlap_epsilon (to embed into the mug)
+ // X ends at handle_thickness + handle_inner_width (where the arc begins)
+ cube([
+ handle_thickness + handle_inner_width + handle_overlap_epsilon, // X-dimension
+ handle_thickness, // Y-thickness
+ handle_total_height // Z-height
+ ], center = [
+ (handle_thickness + handle_inner_width + handle_overlap_epsilon) / 2 - handle_overlap_epsilon, // X-center to align start at -overlap_epsilon
+ 0, // Y-center
+ 0 // Z-center
+ ]);
- // The X-coordinate of the inner face of the handle material, after the mug connection.
- // This is also where the horizontal bars of the D-shape begin.
- x_handle_inner_material_face = x_mug_outer_surface + handle_thickness;
+ // Outer arc part (semi-cylinder)
+ // The arc's straight edge is at X = handle_thickness + handle_inner_width.
+ // We translate to this point for the cylinder's local origin.
+ translate([
+ handle_thickness + handle_inner_width, // X: where the arc's straight edge is
+ 0, // Y
+ 0 // Z
+ ])
+ rotate([90, 0, 0]) { // Rotate cylinder (default along Z) so its axis is along Y, profile in XZ.
+ difference() {
+ cylinder(r = outer_d_arc_radius, h = handle_thickness, center = true);
+ // Cut off the "left" half of the cylinder to form the D-shape arc.
+ // The cube starts outside the cylinder's negative X range to ensure a full cut.
+ translate([-outer_d_arc_radius - handle_overlap_epsilon * 2, 0, 0])
+ cube([outer_d_arc_radius * 2 + handle_overlap_epsilon * 4, handle_thickness * 1.1, outer_d_arc_radius * 2 + handle_overlap_epsilon * 4], center=true);
+ }
+ }
+ }
- // The X-coordinate where the straight part of the finger hole ends and the arc begins.
- // This is the X-coordinate of the "straight edge" of the D-arc.
- x_handle_arc_straight_edge = x_handle_inner_material_face + handle_inner_width;
+ // 2. Inner cut-out shape (finger hole)
+ // This starts after the mug-connecting material, at X = handle_thickness.
+ translate([
+ handle_thickness, // X: Start of finger hole relative to mug's outer surface
+ 0, // Y: centered
+ 0 // Z: centered
+ ]) {
+ union() {
+ // Straight part of the finger hole cut-out
+ cube([
+ handle_inner_width + handle_overlap_epsilon, // X: Inner width + slight overlap into arc for clean cut
+ handle_thickness * 1.1, // Y: Slightly larger than handle_thickness for clean cut
+ handle_inner_height // Z: Inner height
+ ], center=[
+ (handle_inner_width + handle_overlap_epsilon) / 2, // X-center
+ 0, // Y-center
+ 0 // Z-center
+ ]);
- union() {
- // 1. Vertical connecting bar (connects handle to mug)
- // This bar spans the full height of the D-shaped handle.
- // Its X-dimension extends from x_handle_start_embedded to x_handle_inner_material_face.
- translate([
- x_handle_start_embedded, // Starts slightly inside the mug (X)
- handle_y_center - handle_thickness / 2, // Centered on Y axis
- handle_z_center - (handle_inner_height / 2 + handle_thickness) // Bottom Z of the handle
- ]) {
- cube([
- handle_thickness + handle_overlap_epsilon, // X-dimension (handle_thickness + the overlap into mug)
- handle_thickness, // Y-dimension (handle's thickness)
- handle_inner_height + 2 * handle_thickness // Z-dimension (total height of the handle)
- ]);
- }
-
- // 2. Top horizontal bar
- // This bar forms the top part of the D-shape, connecting the vertical bar to the arc.
- // It's extended slightly into the arc region to ensure robust union.
- translate([
- x_handle_inner_material_face, // Starts after the vertical connecting bar (X)
- handle_y_center - handle_thickness / 2, // Centered on Y axis
- handle_z_center + handle_inner_height / 2 // Top Z of the finger hole
- ]) {
- cube([
- handle_inner_width + handle_overlap_epsilon, // X-dimension (width of the finger hole part + overlap)
- handle_thickness, // Y-dimension (handle's thickness)
- handle_thickness // Z-dimension (height of this bar)
- ]);
- }
-
- // 3. Bottom horizontal bar
- // This bar forms the bottom part of the D-shape.
- // It's extended slightly into the arc region to ensure robust union.
- translate([
- x_handle_inner_material_face, // Starts after the vertical connecting bar (X)
- handle_y_center - handle_thickness / 2, // Centered on Y axis
- handle_z_center - handle_inner_height / 2 - handle_thickness // Bottom Z of the finger hole
- ]) {
- cube([
- handle_inner_width + handle_overlap_epsilon, // X-dimension (width of the finger hole part + overlap)
- handle_thickness, // Y-dimension (handle's thickness)
- handle_thickness // Z-dimension (height of this bar)
- ]);
- }
-
- // 4. Outer D-shape arc
- // This creates the curved part of the D-shape handle.
- // It's formed by differencing two concentric cylinders and then cutting one half.
- outer_arc_radius = handle_inner_height / 2 + handle_thickness; // Radius of the outer curve
- inner_arc_radius = handle_inner_height / 2; // Radius of the inner cut for the arc
-
- // The arc is generated such that its straight (left) edge is at X=0 in its local coordinates
- // after the difference and cutting operations.
- // We translate it so its straight edge overlaps with the horizontal bars.
- translate([x_handle_arc_straight_edge - handle_overlap_epsilon, handle_y_center, handle_z_center])
- rotate([90, 0, 0]) { // Rotate so the cylinder's height is along Y, and the arc is in the XZ plane
- difference() {
- // Outer cylinder that defines the overall arc shape (centered in XZ plane)
- cylinder(r = outer_arc_radius, h = handle_thickness, center = true);
-
- // Inner cylinder to cut out the inside of the arc, creating a ring shape
- // Use a slightly larger height to ensure a clean cut through the entire handle_thickness
- cylinder(r = inner_arc_radius, h = handle_thickness * 1.01, center = true);
-
- // Cutting cube to remove the 'negative X' half of the ring, forming the D-shape arc.
- // The cylinders are centered at [0,0,0] in this rotated coordinate system.
- // We want to keep the positive X half (right side), so we cut the negative X half (left side).
- // This cube effectively cuts everything from X < ~0.
- // The cube is positioned to cover the negative X half, ensuring a clean cut.
- translate([-outer_arc_radius - 0.1, 0, 0])
- cube([outer_arc_radius + 0.2, handle_thickness * 1.01, outer_arc_radius * 2 + 0.2], center=true);
+ // Inner arc part of the finger hole cut-out
+ // The inner arc's straight edge is at X = handle_inner_width (relative to its own translate).
+ translate([
+ handle_inner_width, // X: where the inner arc's straight edge is
+ 0,
+ 0
+ ])
+ rotate([90, 0, 0]) { // Same rotation as outer arc
+ difference() {
+ cylinder(r = inner_d_arc_radius, h = handle_thickness * 1.1, center = true); // Slightly larger height for clean cut
+ // Cut off the "left" half of the inner cylinder.
+ translate([-inner_d_arc_radius - handle_overlap_epsilon * 2, 0, 0])
+ cube([inner_d_arc_radius * 2 + handle_overlap_epsilon * 4, handle_thickness * 1.2, inner_d_arc_radius * 2 + handle_overlap_epsilon * 4], center=true);
+ }
+ }
+ }
}
- }
- }
- }
+ } // End of difference for the handle
+ } // End of translate for the handle position
+ } // End of mug_handle module
// Assemble the complete mug by combining the body and the handle
union() {
mug_body();
mug_handle();
}
SCAD (134 lines)
// OpenSCAD Mug with Handle
// Global rendering quality (higher value = smoother curves)
$fn = 64;
// Mug body parameters
mug_outer_radius = 80 / 2; // 40mm
mug_inner_radius = 70 / 2; // 35mm
mug_height = 90;
mug_bottom_thickness = 6;
// Handle parameters
handle_thickness = 10; // Thickness of the handle material
handle_inner_width = 25; // Internal width of the finger hole (X direction)
handle_inner_height = 30; // Internal height of the finger hole (Z direction)
// Overlap for robust union between handle and mug body, and between handle components
// A small positive value ensures parts slightly penetrate each other,
// which helps OpenSCAD create a manifold solid and avoids Z-fighting artifacts.
handle_overlap_epsilon = 0.5; // Example: 0.5mm overlap
module mug_body() {
difference() {
// Outer cylinder of the mug
cylinder(h = mug_height, r = mug_outer_radius);
// Inner hollow part
// Lifted by mug_bottom_thickness to create the solid bottom
// Slightly increased height to avoid Z-fighting artifacts on the top surface
translate([0, 0, mug_bottom_thickness])
cylinder(h = mug_height - mug_bottom_thickness + handle_overlap_epsilon, r = mug_inner_radius);
}
}
module mug_handle() {
// Calculate dimensions for the D-shape handle
// Total height of the handle from top edge to bottom edge
handle_total_height = handle_inner_height + 2 * handle_thickness;
// Outer radius of the D-arc (half of total height)
outer_d_arc_radius = handle_total_height / 2;
// Inner radius of the D-arc (half of inner height)
inner_d_arc_radius = handle_inner_height / 2;
// Position the handle:
// Translate its "attachment point" (the X-coordinate where it meets the mug)
// to mug_outer_radius. We subtract handle_overlap_epsilon to embed it slightly.
// Its Y-center is 0 (aligned with mug's Y axis).
// Its Z-center is mug_height / 2 (aligned with mug's height center).
translate([
mug_outer_radius - handle_overlap_epsilon, // X: start slightly inside mug
0, // Y: centered
mug_height / 2 // Z: centered
]) {
// Build the handle using difference between its outer solid shape and its inner cut-out shape.
difference() {
// 1. Outer solid handle shape
union() {
// Rectangular part of the outer handle (from mug to the start of the arc)
// In its local coordinate system:
// X starts at -handle_overlap_epsilon (to embed into the mug)
// X ends at handle_thickness + handle_inner_width (where the arc begins)
cube([
handle_thickness + handle_inner_width + handle_overlap_epsilon, // X-dimension
handle_thickness, // Y-thickness
handle_total_height // Z-height
], center = [
(handle_thickness + handle_inner_width + handle_overlap_epsilon) / 2 - handle_overlap_epsilon, // X-center to align start at -overlap_epsilon
0, // Y-center
0 // Z-center
]);
// Outer arc part (semi-cylinder)
// The arc's straight edge is at X = handle_thickness + handle_inner_width.
// We translate to this point for the cylinder's local origin.
translate([
handle_thickness + handle_inner_width, // X: where the arc's straight edge is
0, // Y
0 // Z
])
rotate([90, 0, 0]) { // Rotate cylinder (default along Z) so its axis is along Y, profile in XZ.
difference() {
cylinder(r = outer_d_arc_radius, h = handle_thickness, center = true);
// Cut off the "left" half of the cylinder to form the D-shape arc.
// The cube starts outside the cylinder's negative X range to ensure a full cut.
translate([-outer_d_arc_radius - handle_overlap_epsilon * 2, 0, 0])
cube([outer_d_arc_radius * 2 + handle_overlap_epsilon * 4, handle_thickness * 1.1, outer_d_arc_radius * 2 + handle_overlap_epsilon * 4], center=true);
}
}
}
// 2. Inner cut-out shape (finger hole)
// This starts after the mug-connecting material, at X = handle_thickness.
translate([
handle_thickness, // X: Start of finger hole relative to mug's outer surface
0, // Y: centered
0 // Z: centered
]) {
union() {
// Straight part of the finger hole cut-out
cube([
handle_inner_width + handle_overlap_epsilon, // X: Inner width + slight overlap into arc for clean cut
handle_thickness * 1.1, // Y: Slightly larger than handle_thickness for clean cut
handle_inner_height // Z: Inner height
], center=[
(handle_inner_width + handle_overlap_epsilon) / 2, // X-center
0, // Y-center
0 // Z-center
]);
// Inner arc part of the finger hole cut-out
// The inner arc's straight edge is at X = handle_inner_width (relative to its own translate).
translate([
handle_inner_width, // X: where the inner arc's straight edge is
0,
0
])
rotate([90, 0, 0]) { // Same rotation as outer arc
difference() {
cylinder(r = inner_d_arc_radius, h = handle_thickness * 1.1, center = true); // Slightly larger height for clean cut
// Cut off the "left" half of the inner cylinder.
translate([-inner_d_arc_radius - handle_overlap_epsilon * 2, 0, 0])
cube([inner_d_arc_radius * 2 + handle_overlap_epsilon * 4, handle_thickness * 1.2, inner_d_arc_radius * 2 + handle_overlap_epsilon * 4], center=true);
}
}
}
}
} // End of difference for the handle
} // End of translate for the handle position
} // End of mug_handle module
// Assemble the complete mug by combining the body and the handle
union() {
mug_body();
mug_handle();
}