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
3 changes: 3 additions & 0 deletions cq_editor/main_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,9 @@ def prepare_actions(self):
self.components["object_tree"].sigAISObjectsSelected.connect(
self.components["viewer"].set_selected
)
self.components["object_tree"].sigHelpersResized.connect(
self.components["viewer"].redisplay
)

self.components["viewer"].sigObjectSelected.connect(
self.components["object_tree"].handleGraphicalSelection
Expand Down
4 changes: 4 additions & 0 deletions cq_editor/widgets/editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,10 @@ def _file_changed(self):
# neovim writes a file by removing it first so must re-add each time
self._watch_paths()

# QFileSystemWater reports deletions as changes
if not Path(self._filename).exists():
return

# Save the current cursor position and selection
cursor = self.textCursor()
cursor_position = cursor.position()
Expand Down
55 changes: 48 additions & 7 deletions cq_editor/widgets/object_tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@
from pyqtgraph.parametertree import Parameter, ParameterTree

from OCP.AIS import AIS_Line
from OCP.Geom import Geom_Line
from OCP.gp import gp_Dir, gp_Pnt, gp_Ax1
from OCP.Geom import Geom_CartesianPoint
from OCP.gp import gp_Pnt
from OCP.Graphic3d import Graphic3d_ZLayerId_Topmost
from OCP.Bnd import Bnd_Box

from ..mixins import ComponentMixin
from ..icons import icon
Expand All @@ -27,6 +29,9 @@
from .viewer import DEFAULT_FACE_COLOR
from ..utils import splitter, layout, get_save_filename

# Default size of the axis helper lines half-length
DEFAULT_AXIS_HALF_LEN = 100.0


class TopTreeItem(QTreeWidgetItem):

Expand Down Expand Up @@ -135,6 +140,7 @@ class ObjectTree(QWidget, ComponentMixin):
sigAISObjectsSelected = pyqtSignal(list)
sigItemChanged = pyqtSignal(QTreeWidgetItem, int)
sigObjectPropertiesChanged = pyqtSignal()
sigHelpersResized = pyqtSignal(list)

def __init__(self, parent):

Expand Down Expand Up @@ -197,6 +203,37 @@ def __init__(self, parent):

self.prepareLayout()

def _axis_points(self, direction, halfLen):
"""Calculates the points needed to draw the axis helper lines"""
p1 = Geom_CartesianPoint(gp_Pnt(*(-halfLen * d for d in direction)))
p2 = Geom_CartesianPoint(gp_Pnt(*(halfLen * d for d in direction)))

return p1, p2

def _rescale_helpers(self):
"""Called to resize the axis helper lines to the model's bounding box."""

# Bounding box over all currently displayed CQ shapes
bbox = Bnd_Box()
for i in range(self.CQ.childCount()):
ais = self.CQ.child(i).ais
if ais is not None:
bbox.Add(ais.BoundingBox())

if bbox.IsVoid():
halfLen = DEFAULT_AXIS_HALF_LEN
else:
halfLen = 2.0 * bbox.CornerMin().Distance(bbox.CornerMax())

resized = []
for item, direction in self._helper_dirs:
p1, p2 = self._axis_points(direction, halfLen)
item.ais.SetPoints(p1, p2) # update geometry in place
resized.append(item.ais)

if resized:
self.sigHelpersResized.emit(resized)

def prepareMenu(self):

self.tree.setContextMenuPolicy(Qt.CustomContextMenu)
Expand Down Expand Up @@ -231,20 +268,22 @@ def toolbarActions(self):
return self._toolbar_actions

def addLines(self):

origin = (0, 0, 0)
ais_list = []
self._helper_dirs = [] # (item, direction) pairs, for later rescaling

for name, color, direction in zip(
("X", "Y", "Z"),
("red", "lawngreen", "blue"),
((1, 0, 0), (0, 1, 0), (0, 0, 1)),
):
line_placement = Geom_Line(gp_Ax1(gp_Pnt(*origin), gp_Dir(*direction)))
line = AIS_Line(line_placement)
p1, p2 = self._axis_points(direction, DEFAULT_AXIS_HALF_LEN)
line = AIS_Line(p1, p2)
line.SetColor(to_occ_color(color))
line.SetZLayer(Graphic3d_ZLayerId_Topmost)

self.Helpers.addChild(ObjectTreeItem(name, ais=line))
item = ObjectTreeItem(name, ais=line)
self.Helpers.addChild(item)
self._helper_dirs.append((item, direction))

ais_list.append(line)

Expand Down Expand Up @@ -309,6 +348,8 @@ def addObjects(self, objects, clean=False, root=None):
else:
self.sigObjectsAdded[list].emit(ais_list)

self._rescale_helpers()

@pyqtSlot(object, str, object)
def addObject(self, obj, name="", options=None):

Expand Down
46 changes: 44 additions & 2 deletions cq_editor/widgets/viewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,16 @@
Graphic3d_StereoMode,
Graphic3d_NOM_JADE,
Graphic3d_MaterialAspect,
Graphic3d_ZLayerId_Topmost,
)
from OCP.AIS import (
AIS_Shaded,
AIS_WireFrame,
AIS_ColoredShape,
AIS_Axis,
AIS_Line,
AIS_ListOfInteractive,
)
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,
Expand All @@ -18,6 +26,7 @@
)
from OCP.Geom import Geom_Axis1Placement
from OCP.gp import gp_Ax3, gp_Dir, gp_Pnt, gp_Ax1
from OCP.Bnd import Bnd_Box

from ..utils import layout, get_save_filename
from ..mixins import ComponentMixin
Expand Down Expand Up @@ -119,6 +128,7 @@ def __init__(self, parent=None):
)

self.setup_default_drawer()
self.setup_helper_layer()
self.updatePreferences()

def setup_default_drawer(self):
Expand All @@ -135,6 +145,16 @@ def setup_default_drawer(self):
line_aspect.SetWidth(DEFAULT_EDGE_WIDTH)
line_aspect.SetColor(DEFAULT_EDGE_COLOR)

def setup_helper_layer(self):
"""
Set up a render layer specifically for the axis helper lines.
"""
viewer = self.canvas.context.CurrentViewer()
settings = viewer.ZLayerSettings(Graphic3d_ZLayerId_Topmost)
settings.SetEnableDepthTest(False) # lines never depth-compare with the model
settings.SetEnableDepthWrite(False) # lines never write into the depth buffer
viewer.SetZLayerSettings(Graphic3d_ZLayerId_Topmost, settings)

def updatePreferences(self, *args):

color1 = to_occ_color(self.preferences["Background color"])
Expand Down Expand Up @@ -314,6 +334,13 @@ def update_item(self, item, col):
else:
ctx.Erase(item.ais, True)

@pyqtSlot(list)
def redisplay(self, ais_list):
ctx = self._get_context()
for ais in ais_list:
if ctx.IsDisplayed(ais):
ctx.Redisplay(ais, True)

@pyqtSlot(list)
def remove_items(self, ais_items):

Expand All @@ -327,8 +354,23 @@ def redraw(self):
self._get_viewer().Redraw()

def fit(self):
ctx = self._get_context()
view = self.canvas.view

displayed = AIS_ListOfInteractive()
ctx.DisplayedObjects(displayed)

self.canvas.view.FitAll()
# Accumulate the bounding box for displayed objects
bbox = Bnd_Box()
for ais in displayed:
if not isinstance(ais, AIS_Line):
bbox.Add(ais.BoundingBox())

# If nothing but the axis helpers are visible, fit to default
if bbox.IsVoid():
view.FitAll()
else:
view.FitAll(bbox, 0.01, True)

def iso_view(self):

Expand Down
2 changes: 1 addition & 1 deletion tests/test_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ def test_render(main):
log = win.components["log"]

# enable CQ reloading
debugger.preferences["Reload CQ"] = True
debugger.preferences["Reload CQ"] = False

# check that object was rendered
assert obj_tree_comp.CQ.childCount() == 1
Expand Down
Loading