#!/usr/bin/env python3 """ toplevel file used for interactive modeling. - `cq-editor ./cq_toplevel.py` - then press green play button to render - edit files externally, and press render again to refresh the view """ import cadquery as cq import argparse import logging import os import subprocess import sys sys.path.append(os.path.join(os.getcwd(), "src")) import case import pinephone import ldtek_battery logger = logging.getLogger(__name__) def svg_export_options(view: str): proj = (1, 1, 1) if view == "front": proj = (0.00, -0.05, 0.10) elif view == "back": proj = (0.00, -0.05, -0.10) elif view == "right": proj = (-0.10, 0.00, 0.00) return dict( width = 1024, height = 1024, marginLeft = 100, marginTop = 10, showAxes = False, # projectionDir controls both the angle and the distance from the camera to the model projectionDir = proj, strokeWidth = 0.25, strokeColor = (255, 0, 0), hiddenColor = (0, 0, 255), showHidden = True, ) def model(): render_phone = os.environ.get("CASE_RENDER_PHONE", "") not in ("", "0") render_phone_only = os.environ.get("CASE_RENDER_PHONE_ONLY", "") not in ("", "0") phone = pinephone.PinePhone() if render_phone_only: return case.orient_for_printing(phone) battery = ldtek_battery.LdtekBattery() return case.case(phone, battery=battery, render_phone=render_phone) def main(): logging.basicConfig() logging.getLogger().setLevel(logging.INFO) parser = argparse.ArgumentParser(description="toplevel cadquery interface") parser.add_argument("--render-phone", action="store_true", help="render the case and also the phone within it; useful to confirm fit visually before printing") parser.add_argument("--render-phone-only", action="store_true", help="render *only* the phone, not even the case") parser.add_argument("--export-stl") parser.add_argument("--export-svg") parser.add_argument("--export-vtk") parser.add_argument("--editor", action="store_true", help="view in cq-editor") args = parser.parse_args() if args.render_phone: os.environ["CASE_RENDER_PHONE"] = "1" if args.render_phone_only: os.environ["CASE_RENDER_PHONE_ONLY"] = "1" logger.info("computing model ...") model_ = model() if args.export_stl: logger.info("exporting stl to %s", args.export_stl) cq.exporters.export(model_, args.export_stl) if args.export_svg: view = None if "front" in args.export_svg: view = "front" elif "back" in args.export_svg: view = "back" elif "right" in args.export_svg: view = "right" logger.info("exporting svg to %s (view: %s)", args.export_svg, str(view)) cq.exporters.export(model_, args.export_svg, opt=svg_export_options(view)) if args.export_vtk: vtk_file = args.export_vtk js_var, _ext = os.path.splitext(os.path.basename(vtk_file)) js_file = f'{vtk_file}.js' logger.info("exporting VTK (for web rendering) to %s", vtk_file) cq.exporters.export(model_, vtk_file, cq.exporters.ExportTypes.VTP) logger.info("wrapping VTK data in a javascript variable (var %s) in %s", js_var, js_file) vtk_data = open(vtk_file).read() with open(js_file, 'w') as js: js.write(f"var {js_var} = `\n") js.write(vtk_data) js.write("`;\n") if args.editor: logger.info("launching cq-editor") subprocess.check_call(["cq-editor", __file__]) if __name__ == "__main__": main() else: result = model()