Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 97 additions & 0 deletions cadquery/vis.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
from . import Shape, Workplane, Assembly, Sketch, Compound, Color
from .occ_impl.exporters.assembly import _vtkRenderWindow
from .occ_impl.jupyter_tools import DEFAULT_COLOR

from typing import Union

from OCP.TopoDS import TopoDS_Shape

from vtkmodules.vtkInteractionWidgets import vtkOrientationMarkerWidget
from vtkmodules.vtkRenderingAnnotation import vtkAxesActor
from vtkmodules.vtkInteractionStyle import vtkInteractorStyleTrackballCamera
from vtkmodules.vtkRenderingCore import vtkMapper, vtkRenderWindowInteractor


def _to_assy(*objs: Union[Shape, Workplane, Assembly, Sketch]) -> Assembly:

assy = Assembly(color=Color(*DEFAULT_COLOR))

for obj in objs:
if isinstance(obj, (Shape, Workplane, Assembly)):
assy.add(obj)
elif isinstance(obj, Sketch):
assy.add(obj._faces)
assy.add(Compound.makeCompound(obj._edges))
assy.add(Compound.makeCompound(obj._wires))
elif isinstance(obj, TopoDS_Shape):
assy.add(Shape(obj))
else:
raise ValueError(f"{obj} has unsupported type {type(obj)}")

return assy


def show(*objs: Union[Shape, Workplane, Assembly, Sketch]):
"""
Show CQ objects using VTK
"""

# construct the assy
assy = _to_assy(*objs)

# create a VTK window
win = _vtkRenderWindow(assy)

win.SetWindowName("CQ viewer")

# rendering related settings
win.SetMultiSamples(16)
vtkMapper.SetResolveCoincidentTopologyToPolygonOffset()
vtkMapper.SetResolveCoincidentTopologyPolygonOffsetParameters(1, 0)
vtkMapper.SetResolveCoincidentTopologyLineOffsetParameters(-1, 0)

# create a VTK interactor
inter = vtkRenderWindowInteractor()
inter.SetInteractorStyle(vtkInteractorStyleTrackballCamera())
inter.SetRenderWindow(win)

# construct an axes indicator
axes = vtkAxesActor()
axes.SetDragable(0)

tp = axes.GetXAxisCaptionActor2D().GetCaptionTextProperty()
tp.SetColor(0, 0, 0)

axes.GetYAxisCaptionActor2D().GetCaptionTextProperty().ShallowCopy(tp)
axes.GetZAxisCaptionActor2D().GetCaptionTextProperty().ShallowCopy(tp)

# 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.SetInteractor(inter)
orient_widget.EnabledOn()
orient_widget.InteractiveOff()

# use gradient background
renderer = win.GetRenderers().GetFirstRenderer()
renderer.GradientBackgroundOn()

# set size and camera
win.SetSize(*win.GetScreenSize())
win.SetPosition(-10, 0)

camera = renderer.GetActiveCamera()
camera.Roll(-35)
camera.Elevation(-45)
renderer.ResetCamera()

# show and return
inter.Initialize()
win.Render()
inter.Start()


# alias
show_object = show
83 changes: 83 additions & 0 deletions tests/test_vis.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
from cadquery import Workplane, Assembly, Sketch
from cadquery.vis import show, show_object

import cadquery.occ_impl.exporters.assembly as assembly
import cadquery.vis as vis

from vtkmodules.vtkRenderingCore import vtkRenderWindow, vtkRenderWindowInteractor

from pytest import fixture, raises


@fixture
def wp():

return Workplane().box(1, 1, 1)


@fixture
def assy(wp):

return Assembly().add(wp)


@fixture
def sk():

return Sketch().circle(1.0)


class FakeInteractor(vtkRenderWindowInteractor):
def Start(self):

pass

def Initialize(self):

pass


class FakeWindow(vtkRenderWindow):
def Render(*args):

pass

def SetSize(*args):

pass

def GetScreenSize(*args):

return 1, 1

def SetPosition(*args):

pass


def test_show(wp, assy, sk, monkeypatch):

# use some dummy vtk objects
monkeypatch.setattr(vis, "vtkRenderWindowInteractor", FakeInteractor)
monkeypatch.setattr(assembly, "vtkRenderWindow", FakeWindow)

# simple smoke test
show(wp)
show(wp.val())
show(assy)
show(sk)
show(wp, sk, assy, wp.val())
show()

with raises(ValueError):
show(1)

show_object(wp)
show_object(wp.val())
show_object(assy)
show_object(sk)
show_object(wp, sk, assy, wp.val())
show_object()

with raises(ValueError):
show_object("a")