Skip to content

Commit

Permalink
Add clipping plane support for X/Y/Z dimensions.
Browse files Browse the repository at this point in the history
* New widget for viewing the clipping plane settings.
* Update the viewer to add clipping planes.
  • Loading branch information
petejohanson committed Mar 21, 2023
1 parent 88d2f7e commit b111555
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 5 deletions.
11 changes: 11 additions & 0 deletions cq_editor/main_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from .widgets.viewer import OCCViewer
from .widgets.console import ConsoleWidget
from .widgets.object_tree import ObjectTree
from .widgets.clipping_planes import ClippingPlanes
from .widgets.traceback_viewer import TracebackPane
from .widgets.debugger import Debugger, LocalsView
from .widgets.cq_object_inspector import CQObjectInspector
Expand Down Expand Up @@ -128,6 +129,13 @@ def prepare_panes(self):
self,
defaultArea='bottom'))

self.registerComponent('clipping_planes',
ClippingPlanes(self),
lambda c: dock(c,
'Clipping Planes',
self,
defaultArea='right'))

for d in self.docks.values():
d.show()

Expand Down Expand Up @@ -259,6 +267,9 @@ def prepare_actions(self):
self.components['debugger'].sigTraceback\
.connect(self.components['traceback_viewer'].addTraceback)

self.components['clipping_planes'].sigClippingPlaneChanged\
.connect(self.components['viewer'].update_clipping_plane)

# trigger re-render when file is modified externally or saved
self.components['editor'].triggerRerender \
.connect(self.components['debugger'].render)
Expand Down
74 changes: 74 additions & 0 deletions cq_editor/widgets/clipping_planes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
from PyQt5.QtWidgets import QApplication, QCheckBox, QHBoxLayout, QLabel, QSpinBox, QWidget
from PyQt5.QtCore import Qt, pyqtSlot, pyqtSignal

from qtconsole.rich_jupyter_widget import RichJupyterWidget

from ..mixins import ComponentMixin
from ..utils import layout

class ClippingPlane(QWidget):

sigClippingPlaneChanged = pyqtSignal(bool,int,bool)

def __init__(self, parent, dimension):
super(ClippingPlane, self).__init__(parent)

self.check = QCheckBox(f"{dimension} Axis", self)
self.spinbox = QSpinBox(self)
self.spinbox.setValue(50)
self.spinbox.setRange(1, 256)
self.invert = QCheckBox("Invert", self)

self.group = layout(self,(self.spinbox,self.invert),layout_type=QHBoxLayout, spacing=5)

layout(self,(self.check,self.group),layout_type=QHBoxLayout, top_widget=self)

self.group.setDisabled(True)
self.check.stateChanged.connect(self.handleChecked)
self.invert.stateChanged.connect(self.handleInvertChecked)
self.spinbox.valueChanged.connect(self.handlePositionChanged)

def handleChecked(self, arg):
self.group.setDisabled(not self.check.checkState())
self.emitState()

def handleInvertChecked(self, arg):
self.emitState()

def handlePositionChanged(self, arg):
self.emitState()

def emitState(self):
self.sigClippingPlaneChanged.emit(self.check.checkState(), self.spinbox.value(), self.invert.checkState())

class ClippingPlanes(QWidget,ComponentMixin):

name = 'Clipping Planes'

sigClippingPlaneChanged = pyqtSignal(str,bool,int,bool)

def __init__(self, parent):
super(ClippingPlanes, self).__init__(parent)

self.x = ClippingPlane(self, "X")
self.x.sigClippingPlaneChanged.connect(self.onXPlaneChanged)
self.y = ClippingPlane(self, "Y")
self.y.sigClippingPlaneChanged.connect(self.onYPlaneChanged)
self.z = ClippingPlane(self, "Z")
self.z.sigClippingPlaneChanged.connect(self.onZPlaneChanged)

layout(self,(self.x,self.y,self.z),top_widget=self)

@pyqtSlot(bool,int,bool)
def onXPlaneChanged(self,enabled,val,inverted):
self.sigClippingPlaneChanged.emit("X",enabled,val,inverted)

@pyqtSlot(bool,int,bool)
def onYPlaneChanged(self,enabled,val,inverted):
self.sigClippingPlaneChanged.emit("Y",enabled,val,inverted)

@pyqtSlot(bool,int,bool)
def onZPlaneChanged(self,enabled,val,inverted):
self.sigClippingPlaneChanged.emit("Z",enabled,val,inverted)


42 changes: 37 additions & 5 deletions cq_editor/widgets/viewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
from PyQt5.QtCore import pyqtSlot, pyqtSignal
from PyQt5.QtGui import QIcon

from OCP.Graphic3d import Graphic3d_Camera, Graphic3d_StereoMode, Graphic3d_NOM_JADE,\
Graphic3d_MaterialAspect
from OCP.Graphic3d import Graphic3d_Camera, Graphic3d_ClipPlane, Graphic3d_StereoMode, Graphic3d_NOM_JADE,\
Graphic3d_MaterialAspect, Graphic3d_Texture2Dplane
from OCP.AIS import AIS_Shaded,AIS_WireFrame, AIS_ColoredShape, AIS_Axis
from OCP.Aspect import Aspect_GDM_Lines, Aspect_GT_Rectangular
from OCP.Quantity import Quantity_NOC_BLACK as BLACK, Quantity_TOC_RGB as TOC_RGB,\
from OCP.Aspect import Aspect_GDM_Lines, Aspect_GT_Rectangular, Aspect_HS_GRID
from OCP.TCollection import TCollection_AsciiString
from OCP.Quantity import Quantity_NOC_BLACK as BLACK, Quantity_NOC_WHITE as WHITE, Quantity_TOC_RGB as TOC_RGB,\
Quantity_Color
from OCP.Geom import Geom_Axis1Placement
from OCP.gp import gp_Ax3, gp_Dir, gp_Pnt, gp_Ax1
from OCP.gp import gp_Ax3, gp_Dir, gp_Pnt, gp_Ax1, gp_Pln

from ..utils import layout, get_save_filename
from ..mixins import ComponentMixin
Expand Down Expand Up @@ -56,6 +57,14 @@ def __init__(self,parent=None):
self.canvas = OCCTWidget()
self.canvas.sigObjectSelected.connect(self.handle_selection)


self.x_clipping_plane = self.setup_clipping_plane('red', gp_Pln(-1, 0.0, 0.0, 100))
self.y_clipping_plane = self.setup_clipping_plane('lawngreen', gp_Pln(0.0, -1, 0.0, 100))
self.z_clipping_plane = self.setup_clipping_plane('blue', gp_Pln(0.0, 0.0, -1, 100))
self.canvas.view.AddClipPlane(self.x_clipping_plane)
self.canvas.view.AddClipPlane(self.y_clipping_plane)
self.canvas.view.AddClipPlane(self.z_clipping_plane)

self.create_actions(self)

self.layout_ = layout(self,
Expand All @@ -66,6 +75,16 @@ def __init__(self,parent=None):
self.setup_default_drawer()
self.updatePreferences()

def setup_clipping_plane(self, color, eq):
cp = Graphic3d_ClipPlane()
cp.SetEquation(eq)
cp.SetCapping(True)
cp.SetCappingColor(to_occ_color(color))
# cp.SetCappingTexture(Graphic3d_Texture2Dplane(TCollection_AsciiString("./clip-texture.png")))
cp.SetOn(False)

return cp

def setup_default_drawer(self):

# set the default color and material
Expand Down Expand Up @@ -369,6 +388,19 @@ def set_selected(self,ais):

self.redraw()

@pyqtSlot(str,bool,int,bool)
def update_clipping_plane(self,plane,enabled,val,inverted):
if plane == "X":
self.x_clipping_plane.SetEquation(gp_Pln(1 if inverted else -1, 0.0, 0.0, val))
self.x_clipping_plane.SetOn(enabled)
elif plane == "Y":
self.y_clipping_plane.SetEquation(gp_Pln(0.0, 1 if inverted else -1, 0.0, val))
self.y_clipping_plane.SetOn(enabled)
elif plane == "Z":
self.z_clipping_plane.SetEquation(gp_Pln(0.0, 0.0, 1 if inverted else -1, val))
self.z_clipping_plane.SetOn(enabled)

self.redraw()

if __name__ == "__main__":

Expand Down

0 comments on commit b111555

Please sign in to comment.