From e97ed36b90c87d1166c25425bfc1841ed5ca3301 Mon Sep 17 00:00:00 2001 From: adam-urbanczyk Date: Fri, 6 Dec 2024 21:08:14 +0100 Subject: [PATCH 1/6] Handle vtkActors --- cadquery/vis.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/cadquery/vis.py b/cadquery/vis.py index 7e9c8d14f..429977feb 100644 --- a/cadquery/vis.py +++ b/cadquery/vis.py @@ -58,6 +58,7 @@ def _split_showables(objs) -> Tuple[List[ShapeLike], List[Vector], List[Location rv_s: List[ShapeLike] = [] rv_v: List[Vector] = [] rv_l: List[Location] = [] + rv_a: List[vtkActor] = [] for el in objs: if instance_of(el, ShapeLike): @@ -66,21 +67,24 @@ def _split_showables(objs) -> Tuple[List[ShapeLike], List[Vector], List[Location rv_v.append(el) elif isinstance(el, Location): rv_l.append(el) + elif isinstance(el, vtkActor): + rv_a.append(el) elif isinstance(el, list): - tmp1, tmp2, tmp3 = _split_showables(el) # split recursively + tmp1, tmp2, tmp3, tmp4 = _split_showables(el) # split recursively rv_s.extend(tmp1) rv_v.extend(tmp2) rv_l.extend(tmp3) + rv_a.extend(tmp4) - return rv_s, rv_v, rv_l + return rv_s, rv_v, rv_l, rv_a def _to_vtk_pts( vecs: List[Vector], size: float = DEFAULT_PT_SIZE, color: str = DEFAULT_PT_COLOR ) -> vtkActor: """ - Convert vectors to vtkActor. + Convert Vectors to vtkActor. """ rv = vtkActor() @@ -110,7 +114,7 @@ def _to_vtk_pts( def _to_vtk_axs(locs: List[Location], scale: float = 0.1) -> vtkActor: """ - Convert vectors to vtkActor. + Convert Locations to vtkActor. """ rv = vtkAssembly() @@ -142,7 +146,7 @@ def show( """ # split objects - shapes, vecs, locs = _split_showables(objs) + shapes, vecs, locs, acts = _split_showables(objs) # construct the assy assy = _to_assy(*shapes, alpha=alpha) @@ -209,6 +213,10 @@ def show( renderer.AddActor(pts) renderer.AddActor(axs) + # add other vtk actors + for a in acts: + renderer.AddActor(a) + # initialize and set size inter.Initialize() win.SetSize(*win.GetScreenSize()) From 1b67a718412e0d06c462ea5c5fa189baecc9fecb Mon Sep 17 00:00:00 2001 From: adam-urbanczyk Date: Fri, 6 Dec 2024 21:32:27 +0100 Subject: [PATCH 2/6] Mypy fix --- cadquery/vis.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cadquery/vis.py b/cadquery/vis.py index 429977feb..df7d9a22f 100644 --- a/cadquery/vis.py +++ b/cadquery/vis.py @@ -50,7 +50,9 @@ def _to_assy(*objs: ShapeLike, alpha: float = 1) -> Assembly: return assy -def _split_showables(objs) -> Tuple[List[ShapeLike], List[Vector], List[Location]]: +def _split_showables( + objs, +) -> Tuple[List[ShapeLike], List[Vector], List[Location], List[vtkActor]]: """ Split into showables and others. """ From da2061a11b0eb11201e340071db75984a61f14cb Mon Sep 17 00:00:00 2001 From: adam-urbanczyk Date: Fri, 6 Dec 2024 21:34:18 +0100 Subject: [PATCH 3/6] Update Showables --- cadquery/vis.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cadquery/vis.py b/cadquery/vis.py index df7d9a22f..e275fcde3 100644 --- a/cadquery/vis.py +++ b/cadquery/vis.py @@ -28,7 +28,9 @@ DEFAULT_PT_COLOR = "darkviolet" ShapeLike = Union[Shape, Workplane, Assembly, Sketch, TopoDS_Shape] -Showable = Union[ShapeLike, List[ShapeLike], Vector, List[Vector]] +Showable = Union[ + ShapeLike, List[ShapeLike], Vector, List[Vector], vtkActor, List[vtkActor] +] def _to_assy(*objs: ShapeLike, alpha: float = 1) -> Assembly: From ef73e0bb049cb59c1ed9776c0886ae3db2c7dff2 Mon Sep 17 00:00:00 2001 From: adam-urbanczyk Date: Fri, 6 Dec 2024 22:01:32 +0100 Subject: [PATCH 4/6] Add specular lighting --- cadquery/vis.py | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/cadquery/vis.py b/cadquery/vis.py index e275fcde3..b15ea7bce 100644 --- a/cadquery/vis.py +++ b/cadquery/vis.py @@ -15,6 +15,7 @@ vtkMapper, vtkRenderWindowInteractor, vtkActor, + vtkProp, vtkPolyDataMapper, vtkAssembly, ) @@ -27,9 +28,13 @@ DEFAULT_PT_SIZE = 7.5 DEFAULT_PT_COLOR = "darkviolet" +SPECULAR = 0.3 +SPECULAR_POWER = 100 +SPECULAR_COLOR = vtkNamedColors().GetColor3d("White") + ShapeLike = Union[Shape, Workplane, Assembly, Sketch, TopoDS_Shape] Showable = Union[ - ShapeLike, List[ShapeLike], Vector, List[Vector], vtkActor, List[vtkActor] + ShapeLike, List[ShapeLike], Vector, List[Vector], vtkProp, List[vtkProp] ] @@ -54,7 +59,7 @@ def _to_assy(*objs: ShapeLike, alpha: float = 1) -> Assembly: def _split_showables( objs, -) -> Tuple[List[ShapeLike], List[Vector], List[Location], List[vtkActor]]: +) -> Tuple[List[ShapeLike], List[Vector], List[Location], List[vtkProp]]: """ Split into showables and others. """ @@ -62,7 +67,7 @@ def _split_showables( rv_s: List[ShapeLike] = [] rv_v: List[Vector] = [] rv_l: List[Location] = [] - rv_a: List[vtkActor] = [] + rv_a: List[vtkProp] = [] for el in objs: if instance_of(el, ShapeLike): @@ -71,7 +76,7 @@ def _split_showables( rv_v.append(el) elif isinstance(el, Location): rv_l.append(el) - elif isinstance(el, vtkActor): + elif isinstance(el, vtkProp): rv_a.append(el) elif isinstance(el, list): tmp1, tmp2, tmp3, tmp4 = _split_showables(el) # split recursively @@ -143,6 +148,7 @@ def show( alpha: float = 1, tolerance: float = 1e-3, edges: bool = False, + specular: bool = True, **kwrags: Any, ): """ @@ -150,7 +156,7 @@ def show( """ # split objects - shapes, vecs, locs, acts = _split_showables(objs) + shapes, vecs, locs, props = _split_showables(objs) # construct the assy assy = _to_assy(*shapes, alpha=alpha) @@ -165,10 +171,18 @@ def show( win.SetWindowName("CQ viewer") # get renderer and actor - if edges: - ren = win.GetRenderers().GetFirstRenderer() - for act in ren.GetActors(): - act.GetProperty().EdgeVisibilityOn() + ren = win.GetRenderers().GetFirstRenderer() + for act in ren.GetActors(): + + propt = act.GetProperty() + + if edges: + propt.EdgeVisibilityOn() + + if specular: + propt.SetSpecular(SPECULAR) + propt.SetSpecularPower(SPECULAR_POWER) + propt.SetSpecularColor(SPECULAR_COLOR) # rendering related settings win.SetMultiSamples(16) @@ -218,8 +232,8 @@ def show( renderer.AddActor(axs) # add other vtk actors - for a in acts: - renderer.AddActor(a) + for p in props: + renderer.AddActor(p) # initialize and set size inter.Initialize() From 7bccca44017df31643ae01e8056afa581b488a7e Mon Sep 17 00:00:00 2001 From: adam-urbanczyk Date: Sun, 8 Dec 2024 19:28:02 +0100 Subject: [PATCH 5/6] Make show non-blocking and add title --- cadquery/vis.py | 47 +++++++++++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/cadquery/vis.py b/cadquery/vis.py index b15ea7bce..aafd2caf6 100644 --- a/cadquery/vis.py +++ b/cadquery/vis.py @@ -1,6 +1,6 @@ from . import Shape, Workplane, Assembly, Sketch, Compound, Color, Vector, Location from .occ_impl.exporters.assembly import _vtkRenderWindow -from .occ_impl.assembly import _loc2vtk +from .occ_impl.assembly import _loc2vtk, toVTK from typing import Union, Any, List, Tuple @@ -22,7 +22,10 @@ from vtkmodules.vtkCommonCore import vtkPoints from vtkmodules.vtkCommonDataModel import vtkCellArray, vtkPolyData from vtkmodules.vtkCommonColor import vtkNamedColors - +from vtkmodules.qt.QVTKRenderWindowInteractor import ( + QVTKRenderWindowInteractor, + QMainWindow, +) DEFAULT_COLOR = [1, 0.8, 0, 1] DEFAULT_PT_SIZE = 7.5 @@ -149,6 +152,7 @@ def show( tolerance: float = 1e-3, edges: bool = False, specular: bool = True, + title: str = "CQ viewer", **kwrags: Any, ): """ @@ -165,14 +169,18 @@ def show( pts = _to_vtk_pts(vecs) axs = _to_vtk_axs(locs, scale=scale) - # create a VTK window - win = _vtkRenderWindow(assy, tolerance=tolerance) + # assy+renderer + renderer = toVTK(assy, tolerance=tolerance) - win.SetWindowName("CQ viewer") + # QT+VTK window boilerplate + qwin = QMainWindow() + widget = QVTKRenderWindowInteractor() + qwin.setCentralWidget(widget) + + widget.GetRenderWindow().AddRenderer(renderer) # get renderer and actor - ren = win.GetRenderers().GetFirstRenderer() - for act in ren.GetActors(): + for act in renderer.GetActors(): propt = act.GetProperty() @@ -185,15 +193,13 @@ def show( propt.SetSpecularColor(SPECULAR_COLOR) # rendering related settings - win.SetMultiSamples(16) vtkMapper.SetResolveCoincidentTopologyToPolygonOffset() vtkMapper.SetResolveCoincidentTopologyPolygonOffsetParameters(1, 0) vtkMapper.SetResolveCoincidentTopologyLineOffsetParameters(-1, 0) # create a VTK interactor - inter = vtkRenderWindowInteractor() + inter = widget.GetRenderWindow().GetInteractor() inter.SetInteractorStyle(vtkInteractorStyleTrackballCamera()) - inter.SetRenderWindow(win) # construct an axes indicator axes = vtkAxesActor() @@ -214,8 +220,11 @@ def show( orient_widget.EnabledOn() orient_widget.InteractiveOff() + # store the widget to prevent it being GCed + widget.axes = orient_widget + # use gradient background - renderer = win.GetRenderers().GetFirstRenderer() + renderer.SetBackground(vtkNamedColors().GetColor3d("white")) renderer.GradientBackgroundOn() # use FXXAA @@ -235,14 +244,16 @@ def show( for p in props: renderer.AddActor(p) - # initialize and set size - inter.Initialize() - win.SetSize(*win.GetScreenSize()) - win.SetPosition(-10, 0) - # show and return - win.Render() - inter.Start() + qwin.setWindowTitle(title) + qwin.showMaximized() + + widget.Initialize() + widget.Start() + + widget.qwin = qwin + + return widget # alias From 107523acaf47940d7d23afcc69892ff6585ff0aa Mon Sep 17 00:00:00 2001 From: adam-urbanczyk Date: Sun, 8 Dec 2024 21:39:03 +0100 Subject: [PATCH 6/6] Return only qwin --- cadquery/vis.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/cadquery/vis.py b/cadquery/vis.py index aafd2caf6..a2600b90c 100644 --- a/cadquery/vis.py +++ b/cadquery/vis.py @@ -174,7 +174,7 @@ def show( # QT+VTK window boilerplate qwin = QMainWindow() - widget = QVTKRenderWindowInteractor() + widget = QVTKRenderWindowInteractor(qwin) qwin.setCentralWidget(widget) widget.GetRenderWindow().AddRenderer(renderer) @@ -214,8 +214,8 @@ def show( # add to an orientation widget orient_widget = vtkOrientationMarkerWidget() orient_widget.SetOrientationMarker(axes) - orient_widget.SetViewport(0.9, 0.0, 1.0, 0.2) - orient_widget.SetZoom(1.1) + orient_widget.SetViewport(0.9, 0, 1.0, 0.2) + orient_widget.SetZoom(1.5) orient_widget.SetInteractor(inter) orient_widget.EnabledOn() orient_widget.InteractiveOff() @@ -251,9 +251,7 @@ def show( widget.Initialize() widget.Start() - widget.qwin = qwin - - return widget + return qwin # alias