diff --git a/Makefile b/Makefile index 5f6b334..0caa1ea 100644 --- a/Makefile +++ b/Makefile @@ -81,11 +81,11 @@ build/web-viewer/index.html: doc.in/index.html build/web-viewer/vtk.js build/web mkdir -p build/web-viewer cp $< $@ -%.svg: cq_toplevel.py src/*.py +%.png: cq_toplevel.py src/*.py mkdir -p "$(@D)" - ./cq_toplevel.py --export-svg $@ + ./cq_toplevel.py --export-png $@ -doc: build/web-viewer/index.html build/images/pinephone_front.svg build/images/pinephone_back.svg build/images/pinephone_right.svg +doc: build/web-viewer/index.html build/images/pinephone_case.png clean: rm -rf build diff --git a/cq_toplevel.py b/cq_toplevel.py index b48dfa6..9eedc22 100755 --- a/cq_toplevel.py +++ b/cq_toplevel.py @@ -20,29 +20,53 @@ import case import pinephone import ldtek_battery +from cadquery.occ_impl.assembly import toVTK +from cadquery.vis import _to_assy, _vtkRenderWindow +from vtkmodules.vtkRenderingCore import vtkRenderWindow, vtkWindowToImageFilter +from vtkmodules.vtkIOImage import vtkPNGWriter + + 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 export_png_image(obj, file_: str): + # obj = obj.val().scale(2) + # obj = obj.transformed(offset=(0, 0, 0)) + assy = _to_assy(obj) + # win = _vtkRenderWindow(assy) + renderer = toVTK(assy) + win = vtkRenderWindow() + # win.SetMultiSamples(16) + # win.SetSize(1024, 1024) + win.AddRenderer(renderer) + win.Render() + camera = renderer.GetActiveCamera() + camera.Roll(-35) + camera.Elevation(-45) + # adjust camera so full object is visible. + # this also resizes the window, potentially changing its aspect ratio. + # it's important that the window has been `Render()`'d at least once by now, + # else it'll adjust the camera based on the wrong aspect ratio. + renderer.ResetCamera() + renderer.SetBackground(0.8, 0.8, 0.8) + + # win.SetPosition(-10, 0) + + win.Render() + + # documented here: + win_to_input = vtkWindowToImageFilter() + win_to_input.SetInput(win) + # win_to_input.SetScale(5) + # win_to_input.SetViewport(0, 0, 5, 5) + win_to_input.SetInputBufferTypeToRGB() + win_to_input.ReadFrontBufferOff() + win_to_input.Update() + + exporter = vtkPNGWriter() + exporter.SetFileName(file_) + exporter.SetInputConnection(win_to_input.GetOutputPort()) + exporter.Write() + def _model(): logger.info("computing model ...") @@ -73,7 +97,7 @@ def main(): 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-png") parser.add_argument("--export-vtk") parser.add_argument("--editor", action="store_true", help="view in cq-editor") @@ -86,26 +110,22 @@ def main(): os.environ["CASE_RENDER_PHONE_ONLY"] = "1" if args.export_stl: + model_ = model() logger.info("exporting stl to %s", args.export_stl) - cq.exporters.export(model(), 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_png: + model_ = model() + logger.info("exporting png to %s", args.export_png) + export_png_image(model_, args.export_png) 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' + model_ = model() logger.info("exporting VTK (for web rendering) to %s", vtk_file) - cq.exporters.export(model(), vtk_file, cq.exporters.ExportTypes.VTP) + 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()