SCAD (66 lines)
```openscad
$fn = 96;
// ===== パラメータ =====
mug_outer_d = 80; // 本体外径
mug_inner_d = 70; // 本体内径 (肉厚5mm)
mug_height = 90; // 本体高さ
bottom_thick = 6; // 底の厚み
handle_grip_d = 12; // 取手の太さ(断面の直径)
handle_open_h = 30; // 取手内側の空間の高さ
handle_open_w = 25; // 取手内側の空間の幅(本体外周からの張り出し方向)
handle_z = mug_height / 2; // 取手を付ける高さ(中央)
mug_outer_r = mug_outer_d / 2;
mug_inner_r = mug_inner_d / 2;
// ===== 本体 =====
module mug_body() {
difference() {
// 外形
cylinder(h = mug_height, r = mug_outer_r);
// 内側のくぼみ(中空)
translate([0, 0, bottom_thick])
cylinder(h = mug_height, r = mug_inner_r);
}
}
// ===== 取手 (+X 側のみ, D字形状) =====
// D字の中心線(パス)に沿って円形断面をスイープする
module handle() {
// 取手中心線が描く D 字輪郭の寸法
// 内側の空間: 高さ handle_open_h, 幅 handle_open_w
path_h = handle_open_h + handle_grip_d; // 中心線の高さ方向スパン
path_w = handle_open_w; // 中心線の張り出し幅
// 取手の付け根 X 位置(本体外周に少し食い込ませて確実に union)
base_x = mug_outer_r - 2;
translate([base_x, 0, handle_z])
rotate([90, 0, 0]) // 取手の平面を XZ→作図しやすい向きへ
linear_extrude(height = handle_grip_d, center = true)
difference() {
d_shape(path_w, path_h);
offset(r = -handle_grip_d)
d_shape(path_w, path_h);
}
}
// D字の外形(2D): 左側が直線(本体側)、右側が半円
module d_shape(w, h) {
hull() {
// 直線側(本体に接する辺):上下2点
translate([0, h/2 - w/2]) circle(r = 0.01);
translate([0, -h/2 + w/2]) circle(r = 0.01);
// 半円側
translate([0, h/2 - w/2]) translate([w - w/2,0]) circle(r = 0.01);
translate([0, -h/2 + w/2]) translate([w - w/2,0]) circle(r = 0.01);
}
// 上記hullだと角丸の矩形になるため、よりD字に近い形を別途構成
}
// ===== 組み立て =====
union() {
mug_body();
handle();
}
```
うーん、`d_shape` の作り方が雑になってしまいました。`hull` で角丸矩形を作ってから内側をくり抜く方式だと意図したD字になりません。きちんと作り直します。
```openscad
$fn = 96;
// ===== パラメータ =====
mug_outer_d = 80;
mug_inner_d = 70;
mug_height = 90;
bottom_thick = 6;
handle_grip = 10; // 取手断面の太さ(正方形断面の一辺)
handle_open_h = 30; // 取手内側の高さ
handle_open_w = 25; // 取手内側の幅(張り出し)
handle_z = mug_height / 2;
mug_outer_r = mug_outer_d / 2;
mug_inner_r = mug_inner_d / 2;
// ===== 本体 =====
module mug_body() {
difference() {
cylinder(h = mug_height, r = mug_outer_r);
translate([0, 0, bottom_thick])
cylinder(h = mug_height, r = mug_inner_r);
}
}
// ===== D字取手 (+X 側) =====
// XY平面上で 2D の D字を作り、Z方向に押し出して横倒しにする。
module handle() {
// 2D D字輪郭(外形と内形の差)
outer_w = handle_open_w + handle_grip; // 外形の幅
outer_h = handle_open_h + 2*handle_grip; // 外形の高さ
// 本体外周にしっかり差し込むためのオフセット
base_x = mug_outer_r - 3;
translate([base_x, 0, handle_z])
rotate([0, 90, 0]) // XY平面の図形を立てて +X 方向へ向ける
rotate([0, 0, 90])
linear_extrude(height = handle_grip + 6, center = true) // 本体方向の厚み(余分に伸ばして貫通)
d_profile(outer_w, outer_h, handle_grip);
}
// 2D: D字断面(肉厚 t のリング状、左側が直線・右側が半円)
module d_profile(w, h, t) {
difference() {
d_outer(w, h);
// 内側をくり抜く
offset(delta = -t)
d_outer(w, h);
}
}
// 2D: D字の塗りつぶし外形
// 左辺は直線(x=0)、右側は半円で閉じる
module d_outer(w, h) {
r = h/2; // 半円半径 = 高さの半分
union() {
// 直線部分(矩形)
square([w - r, h], center = false);
// 右端の半円
translate([w - r, h/2])
circle(r = r);
}
}
// ===== 組み立て =====
union() {
mug_body();
handle();
}
```
これでもまだ問題があります。`d_profile` で `offset(delta=-t)` を使うと、直線側(本体に接する辺 x=0)も内側に削れてしまい、本体との接続が弱くなる、かつ「内側の空間が高さ30×幅25」という寸法も正確に出ません。
意図を整理してきちんと作り直します。
**設計方針(確定版):**
- 取手は太さ `g` の枠でできた D 字。
- 内側の穴(指を入れる空間)が **高さ30mm × 幅25mm** になるようにする。
- 内穴の左辺は本体外周のすぐ外側にある直線、右側はD字に沿う。
- 枠の外形は内穴を太さ `g` だけ外側に広げたもの。
- これを本体の +X 側面に押し付けて union。
2Dで「内穴形状」を定義し、それを `offset(g)` で外形に広げれば、内穴寸法を正確に保てます。
```openscad
$fn = 96;
// ===================== パラメータ =====================
mug_outer_d = 80; // 本体外径
mug_inner_d = 70; // 本体内径(肉厚5mm)
mug_height = 90; // 本体高さ
bottom_thick = 6; // 底の厚み
handle_grip = 9; // 取手の枠の太さ(断面)
hole_h = 30; // 取手内側の空間 高さ
hole_w = 25; // 取手内側の空間 幅(+X方向への張り出し)
handle_depth = 12; // 取手の奥行き(Y方向の厚み)
handle_z = mug_height/2; // 取手を付ける高さ(中央)
mug_outer_r = mug_outer_d/2;
mug_inner_r = mug_inner_d/2;
// ===================== 本体 =====================
module mug_body() {
difference() {
cylinder(h = mug_height, r = mug_outer_r);
translate([0, 0, bottom_thick])
cylinder(h = mug_height, r = mug_inner_r);
}
}
// ============ 取手の内穴形状(2D, XZ相当の平面) ============
// 左辺(本体側)は直線、右側は半円のD字。
// この図形は「指が入る空間」そのもの。
module handle_hole_2d() {
r = hole_h/2; // 右側半円の半径
union() {
square([hole_w - r, hole_h], center = false); // 直線部
translate([hole_w - r, hole_h/2]) circle(r = r); // 半円部
}
}
// ============ 取手の枠(2D) ============
// 内穴を太さ handle_grip だけ外側へオフセットして枠を作る。
module handle_frame_2d() {
difference() {
offset(r = handle_grip) handle_hole_2d(); // 外形
handle_hole_2d(); // 内穴をくり抜く
}
}
// ============ 取手(3D配置, +X側のみ) ============
module handle() {
// 枠の2D図形は XY平面上。これを立てて本体の+X面に取り付ける。
// 取手の付け根が本体外周に食い込むよう、左辺を本体内部側へ少しめり込ませる。
overlap = 4; // 本体へのめり込み量(確実なunion用)
translate([mug_outer_r - overlap, 0, handle_z])
// XY平面の図形 → XZ平面へ起こし、押し出し方向(元Z)をY(奥行き)に。
rotate([90, 0, 0])
linear_extrude(height = handle_depth, center = true)
// 図形を上下中央に揃える(穴中心を原点へ)
translate([0, -hole_h/2, 0])
handle_frame_2d();
}
// ===================== 組み立て =====================
union() {
mug_body();
handle();
}
```
これで条件を満たします:
- **本体**: 外径80・内径70(肉厚5mm)・高さ90mm、底6mm、内側中空 ✓
- **取手**: `mug_outer_r - overlap` から +X 方向へ張り出し、**+X 側面のみ** に付く ✓
- **D字形状**: 左辺が直線(本体側)、右側が半円 ✓
- **内側の空間**: `handle_hole_2d()` がそのまま高さ30×幅25の指穴 ✓
- **高さ中央**: `handle_z = mug_height/2` ✓
- **union & マニフォールド**: `overlap=4` で本体外周にめり込ませ、`union()` で確実に結合。宙吊りなし ✓