diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9a9d0a8 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +stl/ diff --git a/flower_pot.py b/flower_pot.py new file mode 100644 index 0000000..43d6936 --- /dev/null +++ b/flower_pot.py @@ -0,0 +1,79 @@ +#!/bin/python3 +from __future__ import annotations + +import subprocess +import sys +from pathlib import Path + + +BASE_DIR = Path(__file__).resolve().parent +SCAD_DIR = BASE_DIR / "flower_pot" +OUT_DIR = BASE_DIR / "stl" + + +def ask_float(prompt: str) -> float: + while True: + try: + value = float(input(prompt).strip()) + if value <= 0: + print("Please enter a positive number.") + continue + return value + except ValueError: + print("Please enter a valid number.") + + +def render_scad(scad_file: Path, out_file: Path, base_radius: float, wall_height: float, wall_height_tray: float) -> None: + cmd = ( + f'openscad ' + f'-D base_radius={base_radius} ' + f'-D wall_height={wall_height} ' + f'-D wall_height_tray={wall_height_tray} ' + f'-o "{out_file}" ' + f'"{scad_file}"' + ) + + result = subprocess.run( + ["bash", "-lc", cmd], + cwd=BASE_DIR, + text=True, + capture_output=True, + ) + + if result.returncode != 0: + print(f"\nFailed to render {scad_file.name}") + if result.stdout: + print(result.stdout) + if result.stderr: + print(result.stderr, file=sys.stderr) + raise SystemExit(result.returncode) + + print(f"Generated {out_file}") + + +def main() -> None: + if not SCAD_DIR.exists(): + raise SystemExit(f"Missing SCAD directory: {SCAD_DIR}") + + base_radius = ask_float("Flower pot radius (base_radius) in mm: ") + wall_height = ask_float("Flower pot height (wall_height) in mm: ") + wall_height_tray = ask_float("Tray height (wall_height_tray) in mm: ") + + OUT_DIR.mkdir(parents=True, exist_ok=True) + + pot_scad = SCAD_DIR / "pot.scad" + tray_scad = SCAD_DIR / "tray.scad" + + if not pot_scad.exists(): + raise SystemExit(f"Missing file: {pot_scad}") + if not tray_scad.exists(): + raise SystemExit(f"Missing file: {tray_scad}") + + render_scad(pot_scad, OUT_DIR / "pot.stl", base_radius, wall_height, wall_height_tray) + render_scad(tray_scad, OUT_DIR / "tray.stl", base_radius, wall_height, wall_height_tray) + + print("\nDone.") + + +if __name__ == "__main__": + main() diff --git a/flower_pot/pot.scad b/flower_pot/pot.scad new file mode 100644 index 0000000..88f0279 --- /dev/null +++ b/flower_pot/pot.scad @@ -0,0 +1,67 @@ +// --- Parameters --- +base_radius = 45; +slot_depth = 2; +floor_thickness = 1.5; + +total_base_h = slot_depth + floor_thickness; + +wall_height = 110; +wall_thickness = 1.5; +flare_angle = 10; + +hole_d = 8; +slot_width = 8; +$fn = 500; + +// --- assembly --- +difference() { + flower_pot_body(); + // radial slots + translate([0, 0, -0.1]) + linear_extrude(height = slot_depth + 0.1) + radial_slots_pattern(); + // drainage holes + translate([0, 0, -0.1]) + linear_extrude(height = total_base_h + 0.2) + holes_pattern(); +} + +// --- modules --- +module flower_pot_body() { + top_x_outer = base_radius + wall_height * tan(flare_angle); + top_x_inner = top_x_outer - (wall_thickness / cos(flare_angle)); + + rotate_extrude() { + polygon(points = [ + [0, 0], + [base_radius, 0], + [top_x_outer, wall_height + total_base_h], + [top_x_inner, wall_height + total_base_h], + [base_radius - wall_thickness, total_base_h], + [0, total_base_h] + ]); + } +} + +module radial_slots_pattern() { + // 6 slots + for(a = [0 : 60 : 359]) { + rotate([0, 0, a]) + translate([base_radius / 2, 0, 0]) + square([base_radius + 5, slot_width], center = true); + } +} + +module holes_pattern() { + union() { + circle(d = hole_d); + + for(r = [18, 30]) { + for(a = [0 : 60 : 359]) { + rotate([0, 0, a]) + translate([r, 0, 0]) + circle(d = hole_d); + } + } + } +} \ No newline at end of file diff --git a/flower_pot/tray.scad b/flower_pot/tray.scad index 01046a7..b424093 100644 --- a/flower_pot/tray.scad +++ b/flower_pot/tray.scad @@ -1,6 +1,6 @@ // --- Parameters --- base_radius = 55; -wall_height = 20; +wall_height_tray = 20; thickness = 1.5; flare_angle = 20; $fn = 500; @@ -11,8 +11,8 @@ rotate_extrude() { polygon(points = [ [0, 0], [base_radius, 0], - [base_radius + wall_height * tan(flare_angle), wall_height], - [base_radius + wall_height * tan(flare_angle) - (thickness / cos(flare_angle)), wall_height], + [base_radius + wall_height_tray * tan(flare_angle), wall_height_tray], + [base_radius + wall_height_tray * tan(flare_angle) - (thickness / cos(flare_angle)), wall_height_tray], [base_radius - thickness, thickness], [0, thickness] ]);