mirror of
https://github.com/jdegenstein/jmwright-CQ-Editor.git
synced 2025-12-21 06:54:26 +01:00
add unused parameters to show_object for compat with ocp_vscode
This commit is contained in:
@@ -1,391 +1,424 @@
|
||||
from PyQt5.QtWidgets import QTreeWidget, QTreeWidgetItem, QAction, QMenu, QWidget, QAbstractItemView
|
||||
from PyQt5.QtCore import Qt, pyqtSlot, pyqtSignal
|
||||
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 ..mixins import ComponentMixin
|
||||
from ..icons import icon
|
||||
from ..cq_utils import make_AIS, export, to_occ_color, is_obj_empty, get_occ_color, set_color
|
||||
from .viewer import DEFAULT_FACE_COLOR
|
||||
from ..utils import splitter, layout, get_save_filename
|
||||
|
||||
class TopTreeItem(QTreeWidgetItem):
|
||||
|
||||
def __init__(self,*args,**kwargs):
|
||||
|
||||
super(TopTreeItem,self).__init__(*args,**kwargs)
|
||||
|
||||
class ObjectTreeItem(QTreeWidgetItem):
|
||||
|
||||
props = [{'name': 'Name', 'type': 'str', 'value': ''},
|
||||
{'name': 'Color', 'type': 'color', 'value': "#f4a824"},
|
||||
{'name': 'Alpha', 'type': 'float', 'value': 0, 'limits': (0,1), 'step': 1e-1},
|
||||
{'name': 'Visible', 'type': 'bool','value': True}]
|
||||
|
||||
def __init__(self,
|
||||
name,
|
||||
ais=None,
|
||||
shape=None,
|
||||
shape_display=None,
|
||||
sig=None,
|
||||
alpha=0.,
|
||||
color='#f4a824',
|
||||
**kwargs):
|
||||
|
||||
super(ObjectTreeItem,self).__init__([name],**kwargs)
|
||||
self.setFlags( self.flags() | Qt.ItemIsUserCheckable)
|
||||
self.setCheckState(0,Qt.Checked)
|
||||
|
||||
self.ais = ais
|
||||
self.shape = shape
|
||||
self.shape_display = shape_display
|
||||
self.sig = sig
|
||||
|
||||
self.properties = Parameter.create(name='Properties',
|
||||
children=self.props)
|
||||
|
||||
self.properties['Name'] = name
|
||||
self.properties['Alpha'] = ais.Transparency()
|
||||
self.properties['Color'] = get_occ_color(ais) if ais and ais.HasColor() else get_occ_color(DEFAULT_FACE_COLOR)
|
||||
self.properties.sigTreeStateChanged.connect(self.propertiesChanged)
|
||||
|
||||
def propertiesChanged(self, properties, changed):
|
||||
|
||||
changed_prop = changed[0][0]
|
||||
|
||||
self.setData(0,0,self.properties['Name'])
|
||||
self.ais.SetTransparency(self.properties['Alpha'])
|
||||
|
||||
if changed_prop.name() == 'Color':
|
||||
set_color(self.ais, to_occ_color(self.properties['Color']))
|
||||
|
||||
self.ais.Redisplay()
|
||||
|
||||
if self.properties['Visible']:
|
||||
self.setCheckState(0,Qt.Checked)
|
||||
else:
|
||||
self.setCheckState(0,Qt.Unchecked)
|
||||
|
||||
if self.sig:
|
||||
self.sig.emit()
|
||||
|
||||
class CQRootItem(TopTreeItem):
|
||||
|
||||
def __init__(self,*args,**kwargs):
|
||||
|
||||
super(CQRootItem,self).__init__(['CQ models'],*args,**kwargs)
|
||||
|
||||
|
||||
class HelpersRootItem(TopTreeItem):
|
||||
|
||||
def __init__(self,*args,**kwargs):
|
||||
|
||||
super(HelpersRootItem,self).__init__(['Helpers'],*args,**kwargs)
|
||||
|
||||
|
||||
class ObjectTree(QWidget,ComponentMixin):
|
||||
|
||||
name = 'Object Tree'
|
||||
_stash = []
|
||||
|
||||
preferences = Parameter.create(name='Preferences',children=[
|
||||
{'name': 'Preserve properties on reload', 'type': 'bool', 'value': False},
|
||||
{'name': 'Clear all before each run', 'type': 'bool', 'value': True},
|
||||
{'name': 'STL precision','type': 'float', 'value': .1}])
|
||||
|
||||
sigObjectsAdded = pyqtSignal([list],[list,bool])
|
||||
sigObjectsRemoved = pyqtSignal(list)
|
||||
sigCQObjectSelected = pyqtSignal(object)
|
||||
sigAISObjectsSelected = pyqtSignal(list)
|
||||
sigItemChanged = pyqtSignal(QTreeWidgetItem,int)
|
||||
sigObjectPropertiesChanged = pyqtSignal()
|
||||
|
||||
def __init__(self,parent):
|
||||
|
||||
super(ObjectTree,self).__init__(parent)
|
||||
|
||||
self.tree = tree = QTreeWidget(self,
|
||||
selectionMode=QAbstractItemView.ExtendedSelection)
|
||||
self.properties_editor = ParameterTree(self)
|
||||
|
||||
tree.setHeaderHidden(True)
|
||||
tree.setItemsExpandable(False)
|
||||
tree.setRootIsDecorated(False)
|
||||
tree.setContextMenuPolicy(Qt.ActionsContextMenu)
|
||||
|
||||
#forward itemChanged singal
|
||||
tree.itemChanged.connect(\
|
||||
lambda item,col: self.sigItemChanged.emit(item,col))
|
||||
#handle visibility changes form tree
|
||||
tree.itemChanged.connect(self.handleChecked)
|
||||
|
||||
self.CQ = CQRootItem()
|
||||
self.Helpers = HelpersRootItem()
|
||||
|
||||
root = tree.invisibleRootItem()
|
||||
root.addChild(self.CQ)
|
||||
root.addChild(self.Helpers)
|
||||
|
||||
tree.expandToDepth(1)
|
||||
|
||||
self._export_STL_action = \
|
||||
QAction('Export as STL',
|
||||
self,
|
||||
enabled=False,
|
||||
triggered=lambda: \
|
||||
self.export('stl',
|
||||
self.preferences['STL precision']))
|
||||
|
||||
self._export_STEP_action = \
|
||||
QAction('Export as STEP',
|
||||
self,
|
||||
enabled=False,
|
||||
triggered=lambda: \
|
||||
self.export('step'))
|
||||
|
||||
self._clear_current_action = QAction(icon('delete'),
|
||||
'Clear current',
|
||||
self,
|
||||
enabled=False,
|
||||
triggered=self.removeSelected)
|
||||
|
||||
self._toolbar_actions = \
|
||||
[QAction(icon('delete-many'),'Clear all',self,triggered=self.removeObjects),
|
||||
self._clear_current_action,]
|
||||
|
||||
self.prepareMenu()
|
||||
|
||||
tree.itemSelectionChanged.connect(self.handleSelection)
|
||||
tree.customContextMenuRequested.connect(self.showMenu)
|
||||
|
||||
self.prepareLayout()
|
||||
|
||||
|
||||
def prepareMenu(self):
|
||||
|
||||
self.tree.setContextMenuPolicy(Qt.CustomContextMenu)
|
||||
|
||||
self._context_menu = QMenu(self)
|
||||
self._context_menu.addActions(self._toolbar_actions)
|
||||
self._context_menu.addActions((self._export_STL_action,
|
||||
self._export_STEP_action))
|
||||
|
||||
def prepareLayout(self):
|
||||
|
||||
self._splitter = splitter((self.tree,self.properties_editor),
|
||||
stretch_factors = (2,1),
|
||||
orientation=Qt.Vertical)
|
||||
layout(self,(self._splitter,),top_widget=self)
|
||||
|
||||
self._splitter.show()
|
||||
|
||||
def showMenu(self,position):
|
||||
|
||||
self._context_menu.exec_(self.tree.viewport().mapToGlobal(position))
|
||||
|
||||
|
||||
def menuActions(self):
|
||||
|
||||
return {'Tools' : [self._export_STL_action,
|
||||
self._export_STEP_action]}
|
||||
|
||||
def toolbarActions(self):
|
||||
|
||||
return self._toolbar_actions
|
||||
|
||||
def addLines(self):
|
||||
|
||||
origin = (0,0,0)
|
||||
ais_list = []
|
||||
|
||||
for name,color,direction in zip(('X','Y','Z'),
|
||||
((0.2,0,0),'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)
|
||||
line.SetColor(to_occ_color(color))
|
||||
|
||||
self.Helpers.addChild(ObjectTreeItem(name,
|
||||
ais=line))
|
||||
|
||||
ais_list.append(line)
|
||||
|
||||
self.sigObjectsAdded.emit(ais_list)
|
||||
|
||||
def _current_properties(self):
|
||||
|
||||
current_params = {}
|
||||
for i in range(self.CQ.childCount()):
|
||||
child = self.CQ.child(i)
|
||||
current_params[child.properties['Name']] = child.properties
|
||||
|
||||
return current_params
|
||||
|
||||
def _restore_properties(self,obj,properties):
|
||||
|
||||
for p in properties[obj.properties['Name']]:
|
||||
obj.properties[p.name()] = p.value()
|
||||
|
||||
@pyqtSlot(dict,bool)
|
||||
@pyqtSlot(dict)
|
||||
def addObjects(self,objects,clean=False,root=None):
|
||||
|
||||
if root is None:
|
||||
root = self.CQ
|
||||
|
||||
request_fit_view = True if root.childCount() == 0 else False
|
||||
preserve_props = self.preferences['Preserve properties on reload']
|
||||
|
||||
if preserve_props:
|
||||
current_props = self._current_properties()
|
||||
|
||||
if clean or self.preferences['Clear all before each run']:
|
||||
self.removeObjects()
|
||||
|
||||
ais_list = []
|
||||
|
||||
#remove empty objects
|
||||
objects_f = {k:v for k,v in objects.items() if not is_obj_empty(v.shape)}
|
||||
|
||||
for name,obj in objects_f.items():
|
||||
ais,shape_display = make_AIS(obj.shape,obj.options)
|
||||
|
||||
child = ObjectTreeItem(name,
|
||||
shape=obj.shape,
|
||||
shape_display=shape_display,
|
||||
ais=ais,
|
||||
sig=self.sigObjectPropertiesChanged)
|
||||
|
||||
if preserve_props and name in current_props:
|
||||
self._restore_properties(child,current_props)
|
||||
|
||||
if child.properties['Visible']:
|
||||
ais_list.append(ais)
|
||||
|
||||
root.addChild(child)
|
||||
|
||||
if request_fit_view:
|
||||
self.sigObjectsAdded[list,bool].emit(ais_list,True)
|
||||
else:
|
||||
self.sigObjectsAdded[list].emit(ais_list)
|
||||
|
||||
@pyqtSlot(object,str,object)
|
||||
def addObject(self,obj,name='',options={}):
|
||||
|
||||
root = self.CQ
|
||||
|
||||
ais,shape_display = make_AIS(obj, options)
|
||||
|
||||
root.addChild(ObjectTreeItem(name,
|
||||
shape=obj,
|
||||
shape_display=shape_display,
|
||||
ais=ais,
|
||||
sig=self.sigObjectPropertiesChanged))
|
||||
|
||||
self.sigObjectsAdded.emit([ais])
|
||||
|
||||
@pyqtSlot(list)
|
||||
@pyqtSlot()
|
||||
def removeObjects(self,objects=None):
|
||||
|
||||
if objects:
|
||||
removed_items_ais = [self.CQ.takeChild(i).ais for i in objects]
|
||||
else:
|
||||
removed_items_ais = [ch.ais for ch in self.CQ.takeChildren()]
|
||||
|
||||
self.sigObjectsRemoved.emit(removed_items_ais)
|
||||
|
||||
@pyqtSlot(bool)
|
||||
def stashObjects(self,action : bool):
|
||||
|
||||
if action:
|
||||
self._stash = self.CQ.takeChildren()
|
||||
removed_items_ais = [ch.ais for ch in self._stash]
|
||||
self.sigObjectsRemoved.emit(removed_items_ais)
|
||||
else:
|
||||
self.removeObjects()
|
||||
self.CQ.addChildren(self._stash)
|
||||
ais_list = [el.ais for el in self._stash]
|
||||
self.sigObjectsAdded.emit(ais_list)
|
||||
|
||||
@pyqtSlot()
|
||||
def removeSelected(self):
|
||||
|
||||
ixs = self.tree.selectedIndexes()
|
||||
rows = [ix.row() for ix in ixs]
|
||||
|
||||
self.removeObjects(rows)
|
||||
|
||||
def export(self,export_type,precision=None):
|
||||
|
||||
items = self.tree.selectedItems()
|
||||
|
||||
# if CQ models is selected get all children
|
||||
if [item for item in items if item is self.CQ]:
|
||||
CQ = self.CQ
|
||||
shapes = [CQ.child(i).shape for i in range(CQ.childCount())]
|
||||
# otherwise collect all selected children of CQ
|
||||
else:
|
||||
shapes = [item.shape for item in items if item.parent() is self.CQ]
|
||||
|
||||
fname = get_save_filename(export_type)
|
||||
if fname != '':
|
||||
export(shapes,export_type,fname,precision)
|
||||
|
||||
@pyqtSlot()
|
||||
def handleSelection(self):
|
||||
|
||||
items =self.tree.selectedItems()
|
||||
if len(items) == 0:
|
||||
self._export_STL_action.setEnabled(False)
|
||||
self._export_STEP_action.setEnabled(False)
|
||||
return
|
||||
|
||||
# emit list of all selected ais objects (might be empty)
|
||||
ais_objects = [item.ais for item in items if item.parent() is self.CQ]
|
||||
self.sigAISObjectsSelected.emit(ais_objects)
|
||||
|
||||
# handle context menu and emit last selected CQ object (if present)
|
||||
item = items[-1]
|
||||
if item.parent() is self.CQ:
|
||||
self._export_STL_action.setEnabled(True)
|
||||
self._export_STEP_action.setEnabled(True)
|
||||
self._clear_current_action.setEnabled(True)
|
||||
self.sigCQObjectSelected.emit(item.shape)
|
||||
self.properties_editor.setParameters(item.properties,
|
||||
showTop=False)
|
||||
self.properties_editor.setEnabled(True)
|
||||
elif item is self.CQ and item.childCount()>0:
|
||||
self._export_STL_action.setEnabled(True)
|
||||
self._export_STEP_action.setEnabled(True)
|
||||
else:
|
||||
self._export_STL_action.setEnabled(False)
|
||||
self._export_STEP_action.setEnabled(False)
|
||||
self._clear_current_action.setEnabled(False)
|
||||
self.properties_editor.setEnabled(False)
|
||||
self.properties_editor.clear()
|
||||
|
||||
@pyqtSlot(list)
|
||||
def handleGraphicalSelection(self,shapes):
|
||||
|
||||
self.tree.clearSelection()
|
||||
|
||||
CQ = self.CQ
|
||||
for i in range(CQ.childCount()):
|
||||
item = CQ.child(i)
|
||||
for shape in shapes:
|
||||
if item.ais.Shape().IsEqual(shape):
|
||||
item.setSelected(True)
|
||||
|
||||
@pyqtSlot(QTreeWidgetItem,int)
|
||||
def handleChecked(self,item,col):
|
||||
|
||||
if type(item) is ObjectTreeItem:
|
||||
if item.checkState(0):
|
||||
item.properties['Visible'] = True
|
||||
else:
|
||||
item.properties['Visible'] = False
|
||||
from PyQt5.QtWidgets import (
|
||||
QTreeWidget,
|
||||
QTreeWidgetItem,
|
||||
QAction,
|
||||
QMenu,
|
||||
QWidget,
|
||||
QAbstractItemView,
|
||||
)
|
||||
from PyQt5.QtCore import Qt, pyqtSlot, pyqtSignal
|
||||
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 ..mixins import ComponentMixin
|
||||
from ..icons import icon
|
||||
from ..cq_utils import (
|
||||
make_AIS,
|
||||
export,
|
||||
to_occ_color,
|
||||
is_obj_empty,
|
||||
get_occ_color,
|
||||
set_color,
|
||||
)
|
||||
from .viewer import DEFAULT_FACE_COLOR
|
||||
from ..utils import splitter, layout, get_save_filename
|
||||
|
||||
|
||||
class TopTreeItem(QTreeWidgetItem):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(TopTreeItem, self).__init__(*args, **kwargs)
|
||||
|
||||
|
||||
class ObjectTreeItem(QTreeWidgetItem):
|
||||
props = [
|
||||
{"name": "Name", "type": "str", "value": ""},
|
||||
{"name": "Color", "type": "color", "value": "#f4a824"},
|
||||
{"name": "Alpha", "type": "float", "value": 0, "limits": (0, 1), "step": 1e-1},
|
||||
{"name": "Visible", "type": "bool", "value": True},
|
||||
]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name,
|
||||
ais=None,
|
||||
shape=None,
|
||||
shape_display=None,
|
||||
sig=None,
|
||||
alpha=0.0,
|
||||
color="#f4a824",
|
||||
**kwargs
|
||||
):
|
||||
super(ObjectTreeItem, self).__init__([name], **kwargs)
|
||||
self.setFlags(self.flags() | Qt.ItemIsUserCheckable)
|
||||
self.setCheckState(0, Qt.Checked)
|
||||
|
||||
self.ais = ais
|
||||
self.shape = shape
|
||||
self.shape_display = shape_display
|
||||
self.sig = sig
|
||||
|
||||
self.properties = Parameter.create(name="Properties", children=self.props)
|
||||
|
||||
self.properties["Name"] = name
|
||||
self.properties["Alpha"] = ais.Transparency()
|
||||
self.properties["Color"] = (
|
||||
get_occ_color(ais)
|
||||
if ais and ais.HasColor()
|
||||
else get_occ_color(DEFAULT_FACE_COLOR)
|
||||
)
|
||||
self.properties.sigTreeStateChanged.connect(self.propertiesChanged)
|
||||
|
||||
def propertiesChanged(self, properties, changed):
|
||||
changed_prop = changed[0][0]
|
||||
|
||||
self.setData(0, 0, self.properties["Name"])
|
||||
self.ais.SetTransparency(self.properties["Alpha"])
|
||||
|
||||
if changed_prop.name() == "Color":
|
||||
set_color(self.ais, to_occ_color(self.properties["Color"]))
|
||||
|
||||
self.ais.Redisplay()
|
||||
|
||||
if self.properties["Visible"]:
|
||||
self.setCheckState(0, Qt.Checked)
|
||||
else:
|
||||
self.setCheckState(0, Qt.Unchecked)
|
||||
|
||||
if self.sig:
|
||||
self.sig.emit()
|
||||
|
||||
|
||||
class CQRootItem(TopTreeItem):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(CQRootItem, self).__init__(["CQ models"], *args, **kwargs)
|
||||
|
||||
|
||||
class HelpersRootItem(TopTreeItem):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(HelpersRootItem, self).__init__(["Helpers"], *args, **kwargs)
|
||||
|
||||
|
||||
class ObjectTree(QWidget, ComponentMixin):
|
||||
name = "Object Tree"
|
||||
_stash = []
|
||||
|
||||
preferences = Parameter.create(
|
||||
name="Preferences",
|
||||
children=[
|
||||
{"name": "Preserve properties on reload", "type": "bool", "value": False},
|
||||
{"name": "Clear all before each run", "type": "bool", "value": True},
|
||||
{"name": "STL precision", "type": "float", "value": 0.1},
|
||||
],
|
||||
)
|
||||
|
||||
sigObjectsAdded = pyqtSignal([list], [list, bool])
|
||||
sigObjectsRemoved = pyqtSignal(list)
|
||||
sigCQObjectSelected = pyqtSignal(object)
|
||||
sigAISObjectsSelected = pyqtSignal(list)
|
||||
sigItemChanged = pyqtSignal(QTreeWidgetItem, int)
|
||||
sigObjectPropertiesChanged = pyqtSignal()
|
||||
|
||||
def __init__(self, parent):
|
||||
super(ObjectTree, self).__init__(parent)
|
||||
|
||||
self.tree = tree = QTreeWidget(
|
||||
self, selectionMode=QAbstractItemView.ExtendedSelection
|
||||
)
|
||||
self.properties_editor = ParameterTree(self)
|
||||
|
||||
tree.setHeaderHidden(True)
|
||||
tree.setItemsExpandable(False)
|
||||
tree.setRootIsDecorated(False)
|
||||
tree.setContextMenuPolicy(Qt.ActionsContextMenu)
|
||||
|
||||
# forward itemChanged singal
|
||||
tree.itemChanged.connect(lambda item, col: self.sigItemChanged.emit(item, col))
|
||||
# handle visibility changes form tree
|
||||
tree.itemChanged.connect(self.handleChecked)
|
||||
|
||||
self.CQ = CQRootItem()
|
||||
self.Helpers = HelpersRootItem()
|
||||
|
||||
root = tree.invisibleRootItem()
|
||||
root.addChild(self.CQ)
|
||||
root.addChild(self.Helpers)
|
||||
|
||||
tree.expandToDepth(1)
|
||||
|
||||
self._export_STL_action = QAction(
|
||||
"Export as STL",
|
||||
self,
|
||||
enabled=False,
|
||||
triggered=lambda: self.export("stl", self.preferences["STL precision"]),
|
||||
)
|
||||
|
||||
self._export_STEP_action = QAction(
|
||||
"Export as STEP", self, enabled=False, triggered=lambda: self.export("step")
|
||||
)
|
||||
|
||||
self._clear_current_action = QAction(
|
||||
icon("delete"),
|
||||
"Clear current",
|
||||
self,
|
||||
enabled=False,
|
||||
triggered=self.removeSelected,
|
||||
)
|
||||
|
||||
self._toolbar_actions = [
|
||||
QAction(
|
||||
icon("delete-many"), "Clear all", self, triggered=self.removeObjects
|
||||
),
|
||||
self._clear_current_action,
|
||||
]
|
||||
|
||||
self.prepareMenu()
|
||||
|
||||
tree.itemSelectionChanged.connect(self.handleSelection)
|
||||
tree.customContextMenuRequested.connect(self.showMenu)
|
||||
|
||||
self.prepareLayout()
|
||||
|
||||
def prepareMenu(self):
|
||||
self.tree.setContextMenuPolicy(Qt.CustomContextMenu)
|
||||
|
||||
self._context_menu = QMenu(self)
|
||||
self._context_menu.addActions(self._toolbar_actions)
|
||||
self._context_menu.addActions(
|
||||
(self._export_STL_action, self._export_STEP_action)
|
||||
)
|
||||
|
||||
def prepareLayout(self):
|
||||
self._splitter = splitter(
|
||||
(self.tree, self.properties_editor),
|
||||
stretch_factors=(2, 1),
|
||||
orientation=Qt.Vertical,
|
||||
)
|
||||
layout(self, (self._splitter,), top_widget=self)
|
||||
|
||||
self._splitter.show()
|
||||
|
||||
def showMenu(self, position):
|
||||
self._context_menu.exec_(self.tree.viewport().mapToGlobal(position))
|
||||
|
||||
def menuActions(self):
|
||||
return {"Tools": [self._export_STL_action, self._export_STEP_action]}
|
||||
|
||||
def toolbarActions(self):
|
||||
return self._toolbar_actions
|
||||
|
||||
def addLines(self):
|
||||
origin = (0, 0, 0)
|
||||
ais_list = []
|
||||
|
||||
for name, color, direction in zip(
|
||||
("X", "Y", "Z"),
|
||||
((0.2, 0, 0), "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)
|
||||
line.SetColor(to_occ_color(color))
|
||||
|
||||
self.Helpers.addChild(ObjectTreeItem(name, ais=line))
|
||||
|
||||
ais_list.append(line)
|
||||
|
||||
self.sigObjectsAdded.emit(ais_list)
|
||||
|
||||
def _current_properties(self):
|
||||
current_params = {}
|
||||
for i in range(self.CQ.childCount()):
|
||||
child = self.CQ.child(i)
|
||||
current_params[child.properties["Name"]] = child.properties
|
||||
|
||||
return current_params
|
||||
|
||||
def _restore_properties(self, obj, properties):
|
||||
for p in properties[obj.properties["Name"]]:
|
||||
obj.properties[p.name()] = p.value()
|
||||
|
||||
@pyqtSlot(dict, bool)
|
||||
@pyqtSlot(dict)
|
||||
def addObjects(self, objects, clean=False, root=None):
|
||||
if root is None:
|
||||
root = self.CQ
|
||||
|
||||
request_fit_view = True if root.childCount() == 0 else False
|
||||
preserve_props = self.preferences["Preserve properties on reload"]
|
||||
|
||||
if preserve_props:
|
||||
current_props = self._current_properties()
|
||||
|
||||
if clean or self.preferences["Clear all before each run"]:
|
||||
self.removeObjects()
|
||||
|
||||
ais_list = []
|
||||
|
||||
# remove empty objects
|
||||
objects_f = {k: v for k, v in objects.items() if not is_obj_empty(v.shape)}
|
||||
|
||||
for name, obj in objects_f.items():
|
||||
ais, shape_display = make_AIS(obj.shape, obj.options)
|
||||
|
||||
child = ObjectTreeItem(
|
||||
name,
|
||||
shape=obj.shape,
|
||||
shape_display=shape_display,
|
||||
ais=ais,
|
||||
sig=self.sigObjectPropertiesChanged,
|
||||
)
|
||||
|
||||
if preserve_props and name in current_props:
|
||||
self._restore_properties(child, current_props)
|
||||
|
||||
if child.properties["Visible"]:
|
||||
ais_list.append(ais)
|
||||
|
||||
root.addChild(child)
|
||||
|
||||
if request_fit_view:
|
||||
self.sigObjectsAdded[list, bool].emit(ais_list, True)
|
||||
else:
|
||||
self.sigObjectsAdded[list].emit(ais_list)
|
||||
|
||||
@pyqtSlot(object, str, object)
|
||||
def addObject(
|
||||
self,
|
||||
obj,
|
||||
name="",
|
||||
options={}, # all following inputs are ignored by cq-editor
|
||||
parent=1,
|
||||
clear=True,
|
||||
port=3939,
|
||||
axes=False,
|
||||
axes0=False,
|
||||
grid=False,
|
||||
ticks=10,
|
||||
ortho=True,
|
||||
transparent=False,
|
||||
default_color=(232, 176, 36),
|
||||
reset_camera=True,
|
||||
zoom=1.0,
|
||||
default_edgecolor=(128, 128, 128),
|
||||
render_edges=True,
|
||||
render_normals=False,
|
||||
render_mates=False,
|
||||
mate_scale=1.0,
|
||||
deviation=0.1,
|
||||
angular_tolerance=0.2,
|
||||
edge_accuracy=5.0,
|
||||
ambient_intensity=1.0,
|
||||
direct_intensity=0.12,
|
||||
):
|
||||
root = self.CQ
|
||||
|
||||
ais, shape_display = make_AIS(obj, options)
|
||||
|
||||
root.addChild(
|
||||
ObjectTreeItem(
|
||||
name,
|
||||
shape=obj,
|
||||
shape_display=shape_display,
|
||||
ais=ais,
|
||||
sig=self.sigObjectPropertiesChanged,
|
||||
)
|
||||
)
|
||||
|
||||
self.sigObjectsAdded.emit([ais])
|
||||
|
||||
@pyqtSlot(list)
|
||||
@pyqtSlot()
|
||||
def removeObjects(self, objects=None):
|
||||
if objects:
|
||||
removed_items_ais = [self.CQ.takeChild(i).ais for i in objects]
|
||||
else:
|
||||
removed_items_ais = [ch.ais for ch in self.CQ.takeChildren()]
|
||||
|
||||
self.sigObjectsRemoved.emit(removed_items_ais)
|
||||
|
||||
@pyqtSlot(bool)
|
||||
def stashObjects(self, action: bool):
|
||||
if action:
|
||||
self._stash = self.CQ.takeChildren()
|
||||
removed_items_ais = [ch.ais for ch in self._stash]
|
||||
self.sigObjectsRemoved.emit(removed_items_ais)
|
||||
else:
|
||||
self.removeObjects()
|
||||
self.CQ.addChildren(self._stash)
|
||||
ais_list = [el.ais for el in self._stash]
|
||||
self.sigObjectsAdded.emit(ais_list)
|
||||
|
||||
@pyqtSlot()
|
||||
def removeSelected(self):
|
||||
ixs = self.tree.selectedIndexes()
|
||||
rows = [ix.row() for ix in ixs]
|
||||
|
||||
self.removeObjects(rows)
|
||||
|
||||
def export(self, export_type, precision=None):
|
||||
items = self.tree.selectedItems()
|
||||
|
||||
# if CQ models is selected get all children
|
||||
if [item for item in items if item is self.CQ]:
|
||||
CQ = self.CQ
|
||||
shapes = [CQ.child(i).shape for i in range(CQ.childCount())]
|
||||
# otherwise collect all selected children of CQ
|
||||
else:
|
||||
shapes = [item.shape for item in items if item.parent() is self.CQ]
|
||||
|
||||
fname = get_save_filename(export_type)
|
||||
if fname != "":
|
||||
export(shapes, export_type, fname, precision)
|
||||
|
||||
@pyqtSlot()
|
||||
def handleSelection(self):
|
||||
items = self.tree.selectedItems()
|
||||
if len(items) == 0:
|
||||
self._export_STL_action.setEnabled(False)
|
||||
self._export_STEP_action.setEnabled(False)
|
||||
return
|
||||
|
||||
# emit list of all selected ais objects (might be empty)
|
||||
ais_objects = [item.ais for item in items if item.parent() is self.CQ]
|
||||
self.sigAISObjectsSelected.emit(ais_objects)
|
||||
|
||||
# handle context menu and emit last selected CQ object (if present)
|
||||
item = items[-1]
|
||||
if item.parent() is self.CQ:
|
||||
self._export_STL_action.setEnabled(True)
|
||||
self._export_STEP_action.setEnabled(True)
|
||||
self._clear_current_action.setEnabled(True)
|
||||
self.sigCQObjectSelected.emit(item.shape)
|
||||
self.properties_editor.setParameters(item.properties, showTop=False)
|
||||
self.properties_editor.setEnabled(True)
|
||||
elif item is self.CQ and item.childCount() > 0:
|
||||
self._export_STL_action.setEnabled(True)
|
||||
self._export_STEP_action.setEnabled(True)
|
||||
else:
|
||||
self._export_STL_action.setEnabled(False)
|
||||
self._export_STEP_action.setEnabled(False)
|
||||
self._clear_current_action.setEnabled(False)
|
||||
self.properties_editor.setEnabled(False)
|
||||
self.properties_editor.clear()
|
||||
|
||||
@pyqtSlot(list)
|
||||
def handleGraphicalSelection(self, shapes):
|
||||
self.tree.clearSelection()
|
||||
|
||||
CQ = self.CQ
|
||||
for i in range(CQ.childCount()):
|
||||
item = CQ.child(i)
|
||||
for shape in shapes:
|
||||
if item.ais.Shape().IsEqual(shape):
|
||||
item.setSelected(True)
|
||||
|
||||
@pyqtSlot(QTreeWidgetItem, int)
|
||||
def handleChecked(self, item, col):
|
||||
if type(item) is ObjectTreeItem:
|
||||
if item.checkState(0):
|
||||
item.properties["Visible"] = True
|
||||
else:
|
||||
item.properties["Visible"] = False
|
||||
|
||||
Reference in New Issue
Block a user