Show: Apply clang format
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
#/***************************************************************************
|
||||
# /***************************************************************************
|
||||
# * Copyright (c) 2018 Victor Titov (DeepSOIC) <vv.titov@gmail.com> *
|
||||
# * *
|
||||
# * This file is part of the FreeCAD CAx development system. *
|
||||
@@ -20,12 +20,14 @@
|
||||
# * *
|
||||
# ***************************************************************************/
|
||||
|
||||
#This is a temporary replacement for C++-powered Container class that should be eventually introduced into FreeCAD
|
||||
# This is a temporary replacement for C++-powered Container class that should be eventually introduced into FreeCAD
|
||||
|
||||
|
||||
class Container(object):
|
||||
"""Container class: a unified interface for container objects, such as Group, Part, Body, or Document.
|
||||
This is a temporary implementation."""
|
||||
Object = None #DocumentObject or Document, the actual container
|
||||
|
||||
Object = None # DocumentObject or Document, the actual container
|
||||
|
||||
def __init__(self, obj):
|
||||
self.Object = obj
|
||||
@@ -33,7 +35,7 @@ class Container(object):
|
||||
def self_check(self):
|
||||
if self.Object is None:
|
||||
raise ValueError("Null!")
|
||||
if not isAContainer(self.Object, links_too= True):
|
||||
if not isAContainer(self.Object, links_too=True):
|
||||
raise NotAContainerError(self.Object)
|
||||
|
||||
def getAllChildren(self):
|
||||
@@ -46,18 +48,18 @@ class Container(object):
|
||||
|
||||
self.self_check()
|
||||
container = self.Object
|
||||
if container.isDerivedFrom('App::Document'):
|
||||
if container.isDerivedFrom("App::Document"):
|
||||
return []
|
||||
elif container.hasExtension('App::OriginGroupExtension'):
|
||||
elif container.hasExtension("App::OriginGroupExtension"):
|
||||
if container.Origin is not None:
|
||||
return [container.Origin]
|
||||
else:
|
||||
return []
|
||||
elif container.isDerivedFrom('App::Origin'):
|
||||
elif container.isDerivedFrom("App::Origin"):
|
||||
return container.OriginFeatures
|
||||
elif container.hasExtension('App::GroupExtension'):
|
||||
elif container.hasExtension("App::GroupExtension"):
|
||||
return []
|
||||
elif container.hasChildElement(): # Link
|
||||
elif container.hasChildElement(): # Link
|
||||
return []
|
||||
raise RuntimeError("getStaticChildren: unexpected container type!")
|
||||
|
||||
@@ -66,7 +68,7 @@ class Container(object):
|
||||
self.self_check()
|
||||
container = self.Object
|
||||
|
||||
if container.isDerivedFrom('App::Document'):
|
||||
if container.isDerivedFrom("App::Document"):
|
||||
# find all objects not contained by any Part or Body
|
||||
result = set(container.Objects)
|
||||
for obj in container.Objects:
|
||||
@@ -74,18 +76,18 @@ class Container(object):
|
||||
children = set(Container(obj).getAllChildren())
|
||||
result = result - children
|
||||
return list(result)
|
||||
elif container.hasExtension('App::GroupExtension'):
|
||||
elif container.hasExtension("App::GroupExtension"):
|
||||
result = container.Group
|
||||
if container.hasExtension('App::GeoFeatureGroupExtension'):
|
||||
#geofeaturegroup's group contains all objects within the CS, we don't want that
|
||||
if container.hasExtension("App::GeoFeatureGroupExtension"):
|
||||
# geofeaturegroup's group contains all objects within the CS, we don't want that
|
||||
result = [obj for obj in result if obj.getParentGroup() is not container]
|
||||
return result
|
||||
elif container.isDerivedFrom('App::Origin'):
|
||||
elif container.isDerivedFrom("App::Origin"):
|
||||
return []
|
||||
elif container.hasChildElement():
|
||||
result = []
|
||||
for sub in container.getSubObjects(1):
|
||||
sobj = container.getSubObject(sub,retType=1)
|
||||
sobj = container.getSubObject(sub, retType=1)
|
||||
if sobj:
|
||||
result.append(sobj)
|
||||
return result
|
||||
@@ -97,11 +99,11 @@ class Container(object):
|
||||
self.self_check()
|
||||
container = self.Object
|
||||
|
||||
if container.isDerivedFrom('App::Document'):
|
||||
return True #Document is a special thing... is it a CS or not is a matter of coding convenience.
|
||||
elif container.hasExtension('App::GeoFeatureGroupExtension'):
|
||||
if container.isDerivedFrom("App::Document"):
|
||||
return True # Document is a special thing... is it a CS or not is a matter of coding convenience.
|
||||
elif container.hasExtension("App::GeoFeatureGroupExtension"):
|
||||
return True
|
||||
elif container.hasChildElement(): # Link
|
||||
elif container.hasChildElement(): # Link
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
@@ -111,13 +113,13 @@ class Container(object):
|
||||
self.self_check()
|
||||
container = self.Object
|
||||
|
||||
if container.isDerivedFrom('App::Document'):
|
||||
return True #Document is a special thing... Return value is a matter of coding convenience.
|
||||
elif container.hasExtension('App::GeoFeatureGroupExtension'):
|
||||
if container.isDerivedFrom("App::Document"):
|
||||
return True # Document is a special thing... Return value is a matter of coding convenience.
|
||||
elif container.hasExtension("App::GeoFeatureGroupExtension"):
|
||||
return True
|
||||
elif container.isDerivedFrom('App::Origin'):
|
||||
elif container.isDerivedFrom("App::Origin"):
|
||||
return True
|
||||
elif container.hasChildElement(): # Link
|
||||
elif container.hasChildElement(): # Link
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
@@ -134,15 +136,15 @@ class Container(object):
|
||||
container = self.Object
|
||||
return _getMetacontainerChildren(self, Container.isAVisGroup)
|
||||
|
||||
def isChildVisible(self,obj):
|
||||
def isChildVisible(self, obj):
|
||||
container = self.Object
|
||||
isElementVisible = getattr(container,'isElementVisible',None)
|
||||
isElementVisible = getattr(container, "isElementVisible", None)
|
||||
if not isElementVisible:
|
||||
return obj.Visibility
|
||||
vis = isElementVisible(obj.Name)
|
||||
if vis < 0:
|
||||
return obj.Visibility
|
||||
return vis>0
|
||||
return vis > 0
|
||||
|
||||
def hasObject(self, obj):
|
||||
"""Returns True if the container contains specified object directly."""
|
||||
@@ -151,6 +153,7 @@ class Container(object):
|
||||
def hasObjectRecursive(self, obj):
|
||||
return self.Object in ContainerChain(obj)
|
||||
|
||||
|
||||
def _getMetacontainerChildren(container, isrightcontainer_func):
|
||||
"""Gathers up children of metacontainer - a container structure formed by containers of specific type.
|
||||
For example, coordinate systems form a kind of container structure.
|
||||
@@ -159,9 +162,9 @@ def _getMetacontainerChildren(container, isrightcontainer_func):
|
||||
isrightcontainer_func: a function f(cnt)->bool, where cnt is a Container object."""
|
||||
|
||||
result = []
|
||||
list_traversing_now = [container] #list of Container instances
|
||||
list_to_be_traversed_next = [] #list of Container instances
|
||||
visited_containers = set([container.Object]) #set of DocumentObjects
|
||||
list_traversing_now = [container] # list of Container instances
|
||||
list_to_be_traversed_next = [] # list of Container instances
|
||||
visited_containers = set([container.Object]) # set of DocumentObjects
|
||||
|
||||
while len(list_traversing_now) > 0:
|
||||
list_to_be_traversed_next = []
|
||||
@@ -178,26 +181,26 @@ def _getMetacontainerChildren(container, isrightcontainer_func):
|
||||
return result
|
||||
|
||||
|
||||
|
||||
def isAContainer(obj, links_too = False):
|
||||
'''isAContainer(obj, links_too): returns True if obj is an object container, such as
|
||||
def isAContainer(obj, links_too=False):
|
||||
"""isAContainer(obj, links_too): returns True if obj is an object container, such as
|
||||
Group, Part, Body. The important characteristic of an object being a
|
||||
container is that it can be activated to receive new objects. Documents
|
||||
are considered containers, too.
|
||||
If links_too, App::Link objects are considered containers, too. Then, container tree
|
||||
isn't necessarily a tree.'''
|
||||
isn't necessarily a tree."""
|
||||
|
||||
if obj.isDerivedFrom('App::Document'):
|
||||
if obj.isDerivedFrom("App::Document"):
|
||||
return True
|
||||
if obj.hasExtension('App::GroupExtension'):
|
||||
if obj.hasExtension("App::GroupExtension"):
|
||||
return True
|
||||
if obj.isDerivedFrom('App::Origin'):
|
||||
if obj.isDerivedFrom("App::Origin"):
|
||||
return True
|
||||
if obj.hasChildElement():
|
||||
return True if links_too else False
|
||||
return False
|
||||
|
||||
#from Part-o-magic...
|
||||
|
||||
# from Part-o-magic...
|
||||
def ContainerOf(obj):
|
||||
"""ContainerOf(obj): returns the container that immediately has obj."""
|
||||
cnt = None
|
||||
@@ -211,17 +214,19 @@ def ContainerOf(obj):
|
||||
return obj.Document
|
||||
return cnt
|
||||
|
||||
|
||||
def getVisGroupOf(obj):
|
||||
chain = VisGroupChain(obj)
|
||||
return chain[-1]
|
||||
|
||||
#from Part-o-magic... over-engineered, but proven to work
|
||||
def ContainerChain(feat):
|
||||
'''ContainerChain(feat): container path to feat (not including feat itself).
|
||||
Last container directly contains the feature.
|
||||
Example of output: [<document>,<SuperPart>,<Part>,<Body>]'''
|
||||
|
||||
if feat.isDerivedFrom('App::Document'):
|
||||
# from Part-o-magic... over-engineered, but proven to work
|
||||
def ContainerChain(feat):
|
||||
"""ContainerChain(feat): container path to feat (not including feat itself).
|
||||
Last container directly contains the feature.
|
||||
Example of output: [<document>,<SuperPart>,<Part>,<Body>]"""
|
||||
|
||||
if feat.isDerivedFrom("App::Document"):
|
||||
return []
|
||||
|
||||
list_traversing_now = [feat]
|
||||
@@ -243,18 +248,25 @@ def ContainerChain(feat):
|
||||
|
||||
return [feat.Document] + list_of_deps[::-1]
|
||||
|
||||
|
||||
def CSChain(feat):
|
||||
cnt_chain = ContainerChain(feat)
|
||||
return [cnt for cnt in cnt_chain if Container(cnt).isACS()]
|
||||
|
||||
|
||||
def VisGroupChain(feat):
|
||||
cnt_chain = ContainerChain(feat)
|
||||
return [cnt for cnt in cnt_chain if Container(cnt).isAVisGroup()]
|
||||
|
||||
|
||||
class ContainerError(RuntimeError):
|
||||
pass
|
||||
|
||||
|
||||
class NotAContainerError(ContainerError):
|
||||
def __init__(self, name="None"):
|
||||
ContainerError.__init__(self, "'{}' is not recognized as container".format(name))
|
||||
|
||||
|
||||
class ContainerTreeError(ContainerError):
|
||||
pass
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#/***************************************************************************
|
||||
# /***************************************************************************
|
||||
# * Copyright (c) 2016 Victor Titov (DeepSOIC) <vv.titov@gmail.com> *
|
||||
# * *
|
||||
# * This file is part of the FreeCAD CAx development system. *
|
||||
@@ -20,10 +20,11 @@
|
||||
# * *
|
||||
# ***************************************************************************/
|
||||
|
||||
|
||||
def getAllDependencies(feat):
|
||||
'''getAllDependencies(feat): gets all features feat depends on, directly or indirectly.
|
||||
"""getAllDependencies(feat): gets all features feat depends on, directly or indirectly.
|
||||
Returns a list, with deepest dependencies last. feat is not included in the list, except
|
||||
if the feature depends on itself (dependency loop).'''
|
||||
if the feature depends on itself (dependency loop)."""
|
||||
list_traversing_now = [feat]
|
||||
set_of_deps = set()
|
||||
list_of_deps = []
|
||||
@@ -41,10 +42,11 @@ def getAllDependencies(feat):
|
||||
|
||||
return list_of_deps
|
||||
|
||||
|
||||
def getAllDependent(feat):
|
||||
'''getAllDependent(feat): gets all features that depend on feat, directly or indirectly.
|
||||
"""getAllDependent(feat): gets all features that depend on feat, directly or indirectly.
|
||||
Returns a list, with deepest dependencies last. feat is not included in the list, except
|
||||
if the feature depends on itself (dependency loop).'''
|
||||
if the feature depends on itself (dependency loop)."""
|
||||
list_traversing_now = [feat]
|
||||
set_of_deps = set()
|
||||
list_of_deps = []
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#/***************************************************************************
|
||||
# /***************************************************************************
|
||||
# * Copyright (c) 2019 Victor Titov (DeepSOIC) <vv.titov@gmail.com> *
|
||||
# * *
|
||||
# * This file is part of the FreeCAD CAx development system. *
|
||||
@@ -20,6 +20,7 @@
|
||||
# * *
|
||||
# ***************************************************************************/
|
||||
|
||||
|
||||
class SceneDetail(object):
|
||||
"""SceneDetail class: abstract class for tempovis scene save/restore plug-in. An implementation must provide:
|
||||
* data storage (as "data" attribute of the object)
|
||||
@@ -32,7 +33,8 @@ class SceneDetail(object):
|
||||
* test for equality, that checks if .data attributes of two SceneDetail instances are equal
|
||||
* info on if the modification affects what is saved to disk, and thus should be undone temporarily for file writing.
|
||||
"""
|
||||
class_id = ''
|
||||
|
||||
class_id = ""
|
||||
|
||||
data = None
|
||||
doc = None
|
||||
@@ -45,9 +47,9 @@ class SceneDetail(object):
|
||||
def set_doc(self, doc):
|
||||
self.doc = doc
|
||||
|
||||
# <interface>
|
||||
key = None #a string or something alike to use to store/find the entry in TempoVis. For example, a string "{object_name}.{property_name}".
|
||||
affects_persistence = False #True indicate that the changes will be recorded if the doc is saved, and that this detail should be restored for saving
|
||||
# <interface>
|
||||
key = None # a string or something alike to use to store/find the entry in TempoVis. For example, a string "{object_name}.{property_name}".
|
||||
affects_persistence = False # True indicate that the changes will be recorded if the doc is saved, and that this detail should be restored for saving
|
||||
|
||||
def scene_value(self):
|
||||
"""scene_value(): returns the value from the scene"""
|
||||
@@ -62,15 +64,16 @@ class SceneDetail(object):
|
||||
if isinstance(other, self.__class__):
|
||||
return self.data == other.data and self.data is not None
|
||||
else:
|
||||
raise TypeError('{self} can\'t be compared with {other}'
|
||||
.format(self= repr(self), other= repr(other)))
|
||||
# </interface>
|
||||
raise TypeError(
|
||||
"{self} can't be compared with {other}".format(self=repr(self), other=repr(other))
|
||||
)
|
||||
|
||||
# <utility>
|
||||
# </interface>
|
||||
|
||||
# <utility>
|
||||
@property
|
||||
def full_key(self):
|
||||
return (self.class_id, self.doc.Name if self.doc else None, self.key)
|
||||
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self.__eq__(other)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#/***************************************************************************
|
||||
# /***************************************************************************
|
||||
# * Copyright (c) 2019 Victor Titov (DeepSOIC) <vv.titov@gmail.com> *
|
||||
# * *
|
||||
# * This file is part of the FreeCAD CAx development system. *
|
||||
@@ -24,19 +24,21 @@ from Show.SceneDetail import SceneDetail
|
||||
|
||||
import FreeCADGui
|
||||
|
||||
|
||||
class Camera(SceneDetail):
|
||||
"""Camera(doc): TempoVis plugin for saving and restoring camera."""
|
||||
class_id = 'SDCamera'
|
||||
|
||||
class_id = "SDCamera"
|
||||
|
||||
def __init__(self, doc):
|
||||
self.doc = doc
|
||||
self.key = 'the_cam'
|
||||
self.key = "the_cam"
|
||||
|
||||
def _viewer(self):
|
||||
gdoc = FreeCADGui.getDocument(self.doc.Name)
|
||||
v = gdoc.activeView()
|
||||
if not hasattr(v, 'getCamera'):
|
||||
v = gdoc.mdiViewsOfType('Gui::View3DInventor')[0]
|
||||
if not hasattr(v, "getCamera"):
|
||||
v = gdoc.mdiViewsOfType("Gui::View3DInventor")[0]
|
||||
return v
|
||||
|
||||
def scene_value(self):
|
||||
@@ -44,4 +46,3 @@ class Camera(SceneDetail):
|
||||
|
||||
def apply_data(self, val):
|
||||
self._viewer().setCamera(val)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#/***************************************************************************
|
||||
# /***************************************************************************
|
||||
# * Copyright (c) 2019 Victor Titov (DeepSOIC) <vv.titov@gmail.com> *
|
||||
# * *
|
||||
# * This file is part of the FreeCAD CAx development system. *
|
||||
@@ -24,31 +24,35 @@ from Show.SceneDetail import SceneDetail
|
||||
import FreeCAD as App
|
||||
import FreeCADGui as Gui
|
||||
|
||||
|
||||
class ClipPlane(SceneDetail):
|
||||
"""ClipPlane(document, enable = None, placement = None, offset = 0.0):
|
||||
TempoVis plugin for applying clipping plane to whole project except edit root.
|
||||
enable can be 0 for disable, 1 for enable, and -1 for toggle
|
||||
(FIXME: toggle value support is a hack for while we can't read out the current state)."""
|
||||
|
||||
class_id = 'SDClipPlane'
|
||||
key = ''
|
||||
class_id = "SDClipPlane"
|
||||
key = ""
|
||||
|
||||
def __init__(self, document, enable = None, placement = None, offset = 0.0):
|
||||
def __init__(self, document, enable=None, placement=None, offset=0.0):
|
||||
self.doc = document
|
||||
if enable is not None:
|
||||
if placement is not None and offset != 0.0:
|
||||
placement = placement.copy()
|
||||
dir = placement.Rotation.multVec(App.Vector(0,0,1))
|
||||
placement.Base = placement.Base + dir*offset
|
||||
dir = placement.Rotation.multVec(App.Vector(0, 0, 1))
|
||||
placement.Base = placement.Base + dir * offset
|
||||
self.data = (enable, placement)
|
||||
|
||||
def scene_value(self):
|
||||
return (0, None) #hack. For until there is a way to easily query the plane, this should be good enough.
|
||||
return (
|
||||
0,
|
||||
None,
|
||||
) # hack. For until there is a way to easily query the plane, this should be good enough.
|
||||
|
||||
def apply_data(self, val):
|
||||
enable, pla = val
|
||||
if enable != 0:
|
||||
self._viewer().toggleClippingPlane(enable, pla= pla)
|
||||
self._viewer().toggleClippingPlane(enable, pla=pla)
|
||||
else:
|
||||
self._viewer().toggleClippingPlane(enable)
|
||||
|
||||
@@ -58,6 +62,6 @@ class ClipPlane(SceneDetail):
|
||||
else:
|
||||
gdoc = Gui.getDocument(self.doc.Name)
|
||||
v = gdoc.activeView()
|
||||
if not hasattr(v, 'toggleClippingPlane'):
|
||||
v = gdoc.mdiViewsOfType('Gui::View3DInventor')[0]
|
||||
if not hasattr(v, "toggleClippingPlane"):
|
||||
v = gdoc.mdiViewsOfType("Gui::View3DInventor")[0]
|
||||
return v
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#/***************************************************************************
|
||||
# /***************************************************************************
|
||||
# * Copyright (c) 2019 Victor Titov (DeepSOIC) <vv.titov@gmail.com> *
|
||||
# * *
|
||||
# * This file is part of the FreeCAD CAx development system. *
|
||||
@@ -24,14 +24,16 @@ from Show.SceneDetail import SceneDetail
|
||||
|
||||
import FreeCAD as App
|
||||
|
||||
|
||||
class ObjectClipPlane(SceneDetail):
|
||||
"""ObjectClipPlane(object, enable = None, placement = None, offset = 0.0):
|
||||
Plugin for TempoVis for adding clipping planes to individual objects."""
|
||||
class_id = 'SDObjectClipPlane'
|
||||
propname = ''
|
||||
objname = ''
|
||||
|
||||
def __init__(self, object, enable = None, placement = None, offset = 0.0):
|
||||
class_id = "SDObjectClipPlane"
|
||||
propname = ""
|
||||
objname = ""
|
||||
|
||||
def __init__(self, object, enable=None, placement=None, offset=0.0):
|
||||
self.objname = object.Name
|
||||
self.doc = object.Document
|
||||
self.key = self.objname
|
||||
@@ -40,7 +42,7 @@ class ObjectClipPlane(SceneDetail):
|
||||
|
||||
def scene_value(self):
|
||||
vp = self.doc.getObject(self.objname).ViewObject
|
||||
cp = getClipPlaneNode(vp, make_if_missing= False)
|
||||
cp = getClipPlaneNode(vp, make_if_missing=False)
|
||||
if cp is None:
|
||||
return self.val(False)
|
||||
else:
|
||||
@@ -53,16 +55,17 @@ class ObjectClipPlane(SceneDetail):
|
||||
def apply_data(self, val):
|
||||
enable, pldef = val
|
||||
vp = self.doc.getObject(self.objname).ViewObject
|
||||
cp = getClipPlaneNode(vp, make_if_missing= True if enable else False)
|
||||
cp = getClipPlaneNode(vp, make_if_missing=True if enable else False)
|
||||
if cp is None and not enable:
|
||||
return
|
||||
if enable:
|
||||
from pivy import coin
|
||||
|
||||
v, d = pldef
|
||||
cp.plane.setValue(coin.SbPlane(coin.SbVec3f(*v), d))
|
||||
cp.on.setValue(enable)
|
||||
|
||||
def val(self, enable, placement = None, offset = 0.0):
|
||||
def val(self, enable, placement=None, offset=0.0):
|
||||
"""val(enable, placement = None, offset = 0.0): constructs a value from convenient
|
||||
parameters. Placement is in global CS. The cutting will be by XY plane of Placement;
|
||||
the stuff in negative Z is visible and the stuff in positive Z is invisible."""
|
||||
@@ -70,16 +73,20 @@ class ObjectClipPlane(SceneDetail):
|
||||
pldef = None
|
||||
if enable:
|
||||
obj = self.doc.getObject(self.objname)
|
||||
plm_cs = obj.getGlobalPlacement().multiply(obj.Placement.inverse()) # placement of CS the object is in
|
||||
plm_cs = obj.getGlobalPlacement().multiply(
|
||||
obj.Placement.inverse()
|
||||
) # placement of CS the object is in
|
||||
plm_plane = plm_cs.inverse().multiply(placement)
|
||||
pldef = placement2plane(plm_plane, offset)
|
||||
return (enable, pldef if enable else None)
|
||||
|
||||
def getClipPlaneNode(viewprovider, make_if_missing = True):
|
||||
|
||||
def getClipPlaneNode(viewprovider, make_if_missing=True):
|
||||
from pivy import coin
|
||||
|
||||
sa = coin.SoSearchAction()
|
||||
sa.setType(coin.SoClipPlane.getClassTypeId())
|
||||
sa.setName('TVClipPlane')
|
||||
sa.setName("TVClipPlane")
|
||||
sa.traverse(viewprovider.RootNode)
|
||||
if sa.isFound() and sa.getPath().getLength() == 1:
|
||||
return sa.getPath().getTail()
|
||||
@@ -88,19 +95,22 @@ def getClipPlaneNode(viewprovider, make_if_missing = True):
|
||||
return None
|
||||
clipplane = coin.SoClipPlane()
|
||||
viewprovider.RootNode.insertChild(clipplane, 0)
|
||||
clipplane.setName('TVClipPlane')
|
||||
clipplane.on.setValue(False) #make sure the plane is not activated by default
|
||||
clipplane.setName("TVClipPlane")
|
||||
clipplane.on.setValue(False) # make sure the plane is not activated by default
|
||||
return clipplane
|
||||
|
||||
|
||||
def placement2plane(placement, offset):
|
||||
"""returns tuple (normal, D) for making coin plane."""
|
||||
normal = placement.Rotation.multVec(App.Vector(0,0,-1))
|
||||
normal = placement.Rotation.multVec(App.Vector(0, 0, -1))
|
||||
D = placement.Base * normal - offset
|
||||
return tuple(normal), D
|
||||
|
||||
def clipPlane(obj, enable, placement = None, offset = 0, tv = None):
|
||||
|
||||
def clipPlane(obj, enable, placement=None, offset=0, tv=None):
|
||||
if tv is None:
|
||||
from Show import TempoVis
|
||||
|
||||
tv = TempoVis(obj.Document)
|
||||
tv.modify(ClipPlane(obj, enable, placement, offset))
|
||||
return tv
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#/***************************************************************************
|
||||
# /***************************************************************************
|
||||
# * Copyright (c) 2019 Victor Titov (DeepSOIC) <vv.titov@gmail.com> *
|
||||
# * *
|
||||
# * This file is part of the FreeCAD CAx development system. *
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
from Show.SceneDetail import SceneDetail
|
||||
|
||||
|
||||
class Pickability(SceneDetail):
|
||||
"""Pickability(object, pickstyle = None):Plugin for TempoVis for altering pick style
|
||||
of objects (i.e., selectability).
|
||||
@@ -29,11 +30,12 @@ class Pickability(SceneDetail):
|
||||
PS_REGULAR = 0 # selectable
|
||||
PS_BOUNDBOX = 1 # selectable, but faster hit testing using bounding box
|
||||
PS_UNPICKABLE = 2 # not selectable and not obstructing."""
|
||||
class_id = 'SDPickability'
|
||||
propname = ''
|
||||
objname = ''
|
||||
|
||||
def __init__(self, object, pickstyle = None):
|
||||
class_id = "SDPickability"
|
||||
propname = ""
|
||||
objname = ""
|
||||
|
||||
def __init__(self, object, pickstyle=None):
|
||||
self.objname = object.Name
|
||||
self.doc = object.Document
|
||||
self.key = self.objname
|
||||
@@ -46,12 +48,15 @@ class Pickability(SceneDetail):
|
||||
def apply_data(self, val):
|
||||
setPickStyle(self.doc.getObject(self.objname).ViewObject, val)
|
||||
|
||||
|
||||
PS_REGULAR = 0
|
||||
PS_BOUNDBOX = 1
|
||||
PS_UNPICKABLE = 2
|
||||
|
||||
def getPickStyleNode(viewprovider, make_if_missing = True):
|
||||
|
||||
def getPickStyleNode(viewprovider, make_if_missing=True):
|
||||
from pivy import coin
|
||||
|
||||
sa = coin.SoSearchAction()
|
||||
sa.setType(coin.SoPickStyle.getClassTypeId())
|
||||
sa.traverse(viewprovider.RootNode)
|
||||
@@ -67,14 +72,14 @@ def getPickStyleNode(viewprovider, make_if_missing = True):
|
||||
|
||||
|
||||
def getPickStyle(viewprovider):
|
||||
ps = getPickStyleNode(viewprovider, make_if_missing= False)
|
||||
ps = getPickStyleNode(viewprovider, make_if_missing=False)
|
||||
if ps is not None:
|
||||
return ps.style.getValue()
|
||||
else:
|
||||
return PS_REGULAR
|
||||
|
||||
|
||||
def setPickStyle(viewprovider, pickstyle):
|
||||
ps = getPickStyleNode(viewprovider, make_if_missing= pickstyle != 0) #coin.SoPickStyle.SHAPE
|
||||
ps = getPickStyleNode(viewprovider, make_if_missing=pickstyle != 0) # coin.SoPickStyle.SHAPE
|
||||
if ps is not None:
|
||||
return ps.style.setValue(pickstyle)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#/***************************************************************************
|
||||
# /***************************************************************************
|
||||
# * Copyright (c) 2019 Victor Titov (DeepSOIC) <vv.titov@gmail.com> *
|
||||
# * *
|
||||
# * This file is part of the FreeCAD CAx development system. *
|
||||
@@ -22,22 +22,23 @@
|
||||
|
||||
from Show.SceneDetail import SceneDetail
|
||||
|
||||
|
||||
class VProperty(SceneDetail):
|
||||
"""VProperty(object, propname, val = None): plugin for TempoVis to alter ViewProvider properties"""
|
||||
|
||||
class_id = 'SDVProperty'
|
||||
class_id = "SDVProperty"
|
||||
affects_persistence = True
|
||||
propname = ''
|
||||
objname = ''
|
||||
propname = ""
|
||||
objname = ""
|
||||
mild_restore = True
|
||||
|
||||
def __init__(self, object, propname, val = None):
|
||||
def __init__(self, object, propname, val=None):
|
||||
self.objname = object.Name
|
||||
self.propname = propname
|
||||
self.doc = object.Document
|
||||
self.key = self.objname + '.' + self.propname
|
||||
self.key = self.objname + "." + self.propname
|
||||
self.data = val
|
||||
if propname == 'LinkVisibility': #seems to not be a property
|
||||
if propname == "LinkVisibility": # seems to not be a property
|
||||
self.affects_persistence = False
|
||||
|
||||
def scene_value(self):
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#/***************************************************************************
|
||||
# /***************************************************************************
|
||||
# * Copyright (c) 2019 Victor Titov (DeepSOIC) <vv.titov@gmail.com> *
|
||||
# * *
|
||||
# * This file is part of the FreeCAD CAx development system. *
|
||||
@@ -24,14 +24,16 @@ from Show.SceneDetail import SceneDetail
|
||||
|
||||
import FreeCADGui
|
||||
|
||||
|
||||
class Workbench(SceneDetail):
|
||||
"""Workbench(wb = None): Plugin for TempoVis for changing active workbench.
|
||||
wb: string, a name of a workbench (e.g. 'SketcherWorkbench')"""
|
||||
class_id = 'SDWorkbench'
|
||||
|
||||
class_id = "SDWorkbench"
|
||||
mild_restore = True
|
||||
|
||||
def __init__(self, wb = None):
|
||||
self.key = 'workbench'
|
||||
def __init__(self, wb=None):
|
||||
self.key = "workbench"
|
||||
if wb is not None:
|
||||
self.data = wb
|
||||
|
||||
@@ -40,4 +42,3 @@ class Workbench(SceneDetail):
|
||||
|
||||
def apply_data(self, val):
|
||||
FreeCADGui.activateWorkbench(val)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#/***************************************************************************
|
||||
# /***************************************************************************
|
||||
# * Copyright (c) 2019 Victor Titov (DeepSOIC) <vv.titov@gmail.com> *
|
||||
# * *
|
||||
# * This file is part of the FreeCAD CAx development system. *
|
||||
@@ -20,6 +20,7 @@
|
||||
# * *
|
||||
# ***************************************************************************/
|
||||
|
||||
|
||||
def is3DObject(obj):
|
||||
"""is3DObject(obj): tests if the object has some 3d geometry.
|
||||
TempoVis is made only for objects in 3d view, so all objects that don't pass this check are ignored by TempoVis."""
|
||||
@@ -29,8 +30,10 @@ def is3DObject(obj):
|
||||
# observation: all viewproviders have transform node, then a switch node. If that switch node contains something, the object has something in 3d view.
|
||||
try:
|
||||
from pivy import coin
|
||||
return obj.ViewObject.SwitchNode.getNumChildren()>0
|
||||
|
||||
return obj.ViewObject.SwitchNode.getNumChildren() > 0
|
||||
except Exception as err:
|
||||
import FreeCAD as App
|
||||
App.Console.PrintWarning(u"Show.ShowUtils.is3DObject error: {err}\n".format(err= str(err)))
|
||||
return True #assume.
|
||||
|
||||
App.Console.PrintWarning("Show.ShowUtils.is3DObject error: {err}\n".format(err=str(err)))
|
||||
return True # assume.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#/***************************************************************************
|
||||
# /***************************************************************************
|
||||
# * Copyright (c) 2019 Victor Titov (DeepSOIC) <vv.titov@gmail.com> *
|
||||
# * *
|
||||
# * This file is part of the FreeCAD CAx development system. *
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
import FreeCAD
|
||||
|
||||
|
||||
class TVObserver(object):
|
||||
def __init__(self):
|
||||
FreeCAD.addDocumentObserver(self)
|
||||
@@ -31,18 +32,22 @@ class TVObserver(object):
|
||||
|
||||
def slotStartSaveDocument(self, doc, filepath):
|
||||
from . import TVStack
|
||||
|
||||
TVStack._slotStartSaveDocument(doc)
|
||||
|
||||
def slotFinishSaveDocument(self, doc, filepath):
|
||||
from . import TVStack
|
||||
|
||||
TVStack._slotFinishSaveDocument(doc)
|
||||
|
||||
def slotDeletedDocument(self, doc):
|
||||
from . import TVStack
|
||||
|
||||
TVStack._slotDeletedDocument(doc)
|
||||
|
||||
#handle module reload
|
||||
if 'observer_singleton' in vars():
|
||||
|
||||
# handle module reload
|
||||
if "observer_singleton" in vars():
|
||||
observer_singleton.stop()
|
||||
|
||||
observer_singleton = TVObserver()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#/***************************************************************************
|
||||
# /***************************************************************************
|
||||
# * Copyright (c) 2019 Victor Titov (DeepSOIC) <vv.titov@gmail.com> *
|
||||
# * *
|
||||
# * This file is part of the FreeCAD CAx development system. *
|
||||
@@ -22,11 +22,12 @@
|
||||
|
||||
import weakref
|
||||
|
||||
global_stacks = {} # dict of TVStacks. key = document name.
|
||||
global_stacks = {} # dict of TVStacks. key = document name.
|
||||
|
||||
|
||||
class TVStack(object):
|
||||
index_LUT = None # Key = id(tempovis_instance). Value = index in the stack.
|
||||
stack = None #list of weakrefs to TV instances. Using weakrefs, so that TempoVis can self-destruct if forgotten.
|
||||
index_LUT = None # Key = id(tempovis_instance). Value = index in the stack.
|
||||
stack = None # list of weakrefs to TV instances. Using weakrefs, so that TempoVis can self-destruct if forgotten.
|
||||
document = None
|
||||
|
||||
_rewind_tv = None
|
||||
@@ -35,13 +36,13 @@ class TVStack(object):
|
||||
self.document = None
|
||||
self.index_LUT = {}
|
||||
self.stack = []
|
||||
from . import TVObserver #to start the observer
|
||||
from . import TVObserver # to start the observer
|
||||
|
||||
def insert(self, tv, index = None):
|
||||
def insert(self, tv, index=None):
|
||||
if index is None:
|
||||
index = len(self.stack)
|
||||
idtv = id(tv)
|
||||
ref = weakref.ref(tv, (lambda _, idtv=idtv, self=self : self._destruction(idtv)))
|
||||
ref = weakref.ref(tv, (lambda _, idtv=idtv, self=self: self._destruction(idtv)))
|
||||
self.stack.insert(index, ref)
|
||||
|
||||
self.rebuild_index(index)
|
||||
@@ -53,7 +54,7 @@ class TVStack(object):
|
||||
try:
|
||||
index = self.index_LUT.get(idtv)
|
||||
except KeyError:
|
||||
#already withdrawn
|
||||
# already withdrawn
|
||||
pass
|
||||
else:
|
||||
self.stack.pop(index)
|
||||
@@ -83,20 +84,19 @@ class TVStack(object):
|
||||
from . import mTempoVis
|
||||
|
||||
index = self.index_LUT[id(tv)] if tv is not None else -1
|
||||
for tvref in self.stack[index + 1 : ]:
|
||||
for tvref in self.stack[index + 1 :]:
|
||||
tv = tvref()
|
||||
if tv.state == mTempoVis.S_ACTIVE:
|
||||
if tv.has(detail):
|
||||
return (tv, tv.data[detail.full_key])
|
||||
return None
|
||||
|
||||
def rebuild_index(self, start = 0):
|
||||
def rebuild_index(self, start=0):
|
||||
if start == 0:
|
||||
self.index_LUT = {}
|
||||
for i in range(start, len(self.stack)):
|
||||
self.index_LUT[id(self.stack[i]())] = i
|
||||
|
||||
|
||||
def purge_dead(self):
|
||||
"""removes dead TV instances from the stack"""
|
||||
n = 0
|
||||
@@ -117,9 +117,11 @@ class TVStack(object):
|
||||
def unwindForSaving(self):
|
||||
from . import mTempoVis
|
||||
|
||||
self.rewindAfterSaving() #just in case there was a failed save before.
|
||||
self.rewindAfterSaving() # just in case there was a failed save before.
|
||||
|
||||
details = {} #dict of detail original values. Key = detail key; value = detail instance with data representing the original value
|
||||
details = (
|
||||
{}
|
||||
) # dict of detail original values. Key = detail key; value = detail instance with data representing the original value
|
||||
for ref in self.stack:
|
||||
tv = ref()
|
||||
for key, detail in tv.data.items():
|
||||
@@ -139,9 +141,11 @@ class TVStack(object):
|
||||
def getSplitSequence(self, tv):
|
||||
"""getSplitSequence(tv): returns (list_before, list_after), neither list includes tv."""
|
||||
index = self.index_LUT[id(tv)]
|
||||
|
||||
def deref(lst):
|
||||
return [ref() for ref in lst]
|
||||
return deref(self.stack[0:index]), deref(self.stack[index+1:])
|
||||
|
||||
return deref(self.stack[0:index]), deref(self.stack[index + 1 :])
|
||||
|
||||
def __getitem__(self, index):
|
||||
return self.stack[index]()
|
||||
@@ -165,7 +169,7 @@ class TVStack(object):
|
||||
return [ref() for ref in self.stack if ref().tag == tag]
|
||||
|
||||
|
||||
def mainStack(document, create_if_missing = True):
|
||||
def mainStack(document, create_if_missing=True):
|
||||
"""mainStack(document, create_if_missing = True):returns the main TVStack instance for provided document"""
|
||||
docname = document.Name
|
||||
|
||||
@@ -175,18 +179,21 @@ def mainStack(document, create_if_missing = True):
|
||||
|
||||
return global_stacks.get(docname, None)
|
||||
|
||||
|
||||
def _slotDeletedDocument(document):
|
||||
docname = document.Name
|
||||
stk = global_stacks.pop(docname, None)
|
||||
if stk is not None:
|
||||
stk.dissolve()
|
||||
|
||||
|
||||
def _slotStartSaveDocument(doc):
|
||||
stk = mainStack(doc, create_if_missing= False)
|
||||
stk = mainStack(doc, create_if_missing=False)
|
||||
if stk is not None:
|
||||
stk.unwindForSaving()
|
||||
|
||||
|
||||
def _slotFinishSaveDocument(doc):
|
||||
stk = mainStack(doc, create_if_missing= False)
|
||||
stk = mainStack(doc, create_if_missing=False)
|
||||
if stk is not None:
|
||||
stk.rewindAfterSaving()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
__doc__ = "Show module: helper code for visibility automation."
|
||||
|
||||
from .mTempoVis import TempoVis
|
||||
from . import DepGraphTools
|
||||
from . import DepGraphTools
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#/***************************************************************************
|
||||
# /***************************************************************************
|
||||
# * Copyright (c) 2016 Victor Titov (DeepSOIC) <vv.titov@gmail.com> *
|
||||
# * *
|
||||
# * This file is part of the FreeCAD CAx development system. *
|
||||
@@ -27,6 +27,7 @@ from . import Containers
|
||||
from . import TVStack
|
||||
|
||||
import FreeCAD as App
|
||||
|
||||
if App.GuiUp:
|
||||
import FreeCADGui as Gui
|
||||
Wrn = lambda msg: App.Console.PrintWarning(msg + "\n")
|
||||
@@ -35,27 +36,36 @@ Log = lambda msg: App.Console.PrintLog(msg + "\n")
|
||||
|
||||
from copy import copy
|
||||
|
||||
S_EMPTY = 0 # TV is initialized, but no changes were done through it
|
||||
S_ACTIVE = 1 # TV has something to be undone
|
||||
S_RESTORED = 2 # TV has been restored
|
||||
S_INTERNAL = 3 # TV instance is being used by another TV instance as a redo data storage
|
||||
S_EMPTY = 0 # TV is initialized, but no changes were done through it
|
||||
S_ACTIVE = 1 # TV has something to be undone
|
||||
S_RESTORED = 2 # TV has been restored
|
||||
S_INTERNAL = 3 # TV instance is being used by another TV instance as a redo data storage
|
||||
|
||||
|
||||
def _printTraceback(err):
|
||||
import sys
|
||||
|
||||
if err is sys.exc_info()[1]:
|
||||
import traceback
|
||||
|
||||
tb = traceback.format_exc()
|
||||
Log(tb)
|
||||
|
||||
|
||||
class MAINSTACK(object):
|
||||
'''it's just a default value definition for TV constructor'''
|
||||
pass
|
||||
class JUST_SAVE(object):
|
||||
'''it's just a default value meaning "save current scene value but don't modify anything"'''
|
||||
"""it's just a default value definition for TV constructor"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class JUST_SAVE(object):
|
||||
'''it's just a default value meaning "save current scene value but don't modify anything"'''
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class TempoVis(object):
|
||||
'''TempoVis - helper object to save visibilities of objects before doing
|
||||
"""TempoVis - helper object to save visibilities of objects before doing
|
||||
some GUI editing, hiding or showing relevant stuff during edit, and
|
||||
then restoring all visibilities after editing.
|
||||
|
||||
@@ -69,25 +79,25 @@ class TempoVis(object):
|
||||
MAINSTACK special value (a global stack for the document will be used), or
|
||||
None (then, the TV is not in any stack, and can be manually instertd into one if desired).
|
||||
|
||||
Any additional keyword args are assigned as attributes. You can use it to immediately set a tag, for example.'''
|
||||
Any additional keyword args are assigned as attributes. You can use it to immediately set a tag, for example."""
|
||||
|
||||
document = None
|
||||
stack = None # reference to stack this TV is in
|
||||
stack = None # reference to stack this TV is in
|
||||
|
||||
data = None # dict. key = ("class_id","key"), value = instance of SceneDetail
|
||||
data_requested = None #same as data, but stores (wanted) values passed to modify()
|
||||
data = None # dict. key = ("class_id","key"), value = instance of SceneDetail
|
||||
data_requested = None # same as data, but stores (wanted) values passed to modify()
|
||||
|
||||
state = S_EMPTY
|
||||
|
||||
tag = '' #stores any user-defined string for identification purposes
|
||||
tag = "" # stores any user-defined string for identification purposes
|
||||
|
||||
def _init_attrs(self):
|
||||
'''initialize member variables to empty values (needed because we can't use mutable initial values when initializing member variables in class definition)'''
|
||||
"""initialize member variables to empty values (needed because we can't use mutable initial values when initializing member variables in class definition)"""
|
||||
self.data = {}
|
||||
self.data_requested = {}
|
||||
|
||||
#<core interface>
|
||||
def __init__(self, document, stack = MAINSTACK, **kwargs):
|
||||
# <core interface>
|
||||
def __init__(self, document, stack=MAINSTACK, **kwargs):
|
||||
self._init_attrs()
|
||||
self.document = document
|
||||
|
||||
@@ -99,40 +109,40 @@ class TempoVis(object):
|
||||
else:
|
||||
stack.insert(self)
|
||||
|
||||
for key,val in kwargs.items():
|
||||
for key, val in kwargs.items():
|
||||
setattr(self, key, val)
|
||||
|
||||
def __del__(self):
|
||||
if self.state == S_ACTIVE:
|
||||
self.restore(ultimate= True)
|
||||
self.restore(ultimate=True)
|
||||
|
||||
def has(self, detail):
|
||||
'''has(self, detail): returns True if this TV has this detail value saved.
|
||||
example: tv.has(VProperty(obj, "Visibility"))'''
|
||||
"""has(self, detail): returns True if this TV has this detail value saved.
|
||||
example: tv.has(VProperty(obj, "Visibility"))"""
|
||||
return detail.full_key in self.data
|
||||
|
||||
def stored_val(self, detail):
|
||||
'''stored_val(self, detail): returns value of detail remembered by this TV. If not, raises KeyError.'''
|
||||
"""stored_val(self, detail): returns value of detail remembered by this TV. If not, raises KeyError."""
|
||||
return self.data[detail.full_key].data
|
||||
|
||||
def save(self, detail, mild_restore = False):
|
||||
'''save(detail, mild_restore = False):saves the scene detail to be restored.
|
||||
def save(self, detail, mild_restore=False):
|
||||
"""save(detail, mild_restore = False):saves the scene detail to be restored.
|
||||
The detail is saved only once; repeated calls are ignored.
|
||||
mild_restore: internal, do not use.'''
|
||||
mild_restore: internal, do not use."""
|
||||
self._change()
|
||||
if not detail.full_key in self.data:
|
||||
#not saved yet
|
||||
tv1, curr = self._value_after(detail, query_scene= True)
|
||||
# not saved yet
|
||||
tv1, curr = self._value_after(detail, query_scene=True)
|
||||
self.data[detail.full_key] = copy(curr)
|
||||
self.data[detail.full_key].mild_restore = mild_restore
|
||||
else:
|
||||
#saved already. Change restore policy, if necessary.
|
||||
# saved already. Change restore policy, if necessary.
|
||||
stored_dt = self.data[detail.full_key]
|
||||
if not mild_restore:
|
||||
stored_dt.mild_restore = False
|
||||
|
||||
def modify(self, detail, mild_restore = None):
|
||||
'''modify(detail, mild_restore = True): modifies scene detail through this TV.
|
||||
def modify(self, detail, mild_restore=None):
|
||||
"""modify(detail, mild_restore = True): modifies scene detail through this TV.
|
||||
The value is provided as an instance of SceneDetail implementation.
|
||||
The procedure takes care to account for the stack - that is, if in a TV applied
|
||||
later than this one this detail was changed too, the value saved therein is altered,
|
||||
@@ -141,7 +151,7 @@ class TempoVis(object):
|
||||
mild_restore: if True, when restoring later, checks if the value was changed
|
||||
by user after last call to modify(), and doesn't restore if it was changed.
|
||||
|
||||
Example: tv.modify(VProperty(obj, "Visibility", True))'''
|
||||
Example: tv.modify(VProperty(obj, "Visibility", True))"""
|
||||
|
||||
self._change()
|
||||
|
||||
@@ -162,36 +172,35 @@ class TempoVis(object):
|
||||
if detail.mild_restore:
|
||||
self.data_requested[detail.full_key] = copy(detail)
|
||||
|
||||
def restoreDetail(self, detail, ultimate = False):
|
||||
'''restoreDetail(detail, ultimate = False): restores a specific scene detail.
|
||||
def restoreDetail(self, detail, ultimate=False):
|
||||
"""restoreDetail(detail, ultimate = False): restores a specific scene detail.
|
||||
ultimate: if true, the saved value is cleaned out.
|
||||
If the detail is not found, nothing is done.
|
||||
'''
|
||||
"""
|
||||
if not self.has(detail):
|
||||
return
|
||||
self._restore_detail(detail)
|
||||
if ultimate:
|
||||
self.forgetDetail(detail)
|
||||
|
||||
|
||||
def forgetDetail(self, detail):
|
||||
'''forgetDetail(detail): ditches a saved detail value, making the change done through this TV permanent.'''
|
||||
"""forgetDetail(detail): ditches a saved detail value, making the change done through this TV permanent."""
|
||||
self.data.pop(detail.full_key, None)
|
||||
self.data_requested.pop(detail.full_key, None)
|
||||
|
||||
def forget(self):
|
||||
'''forget(self): clears this TV, making all changes done through it permanent.
|
||||
Also, withdraws the TV from the stack.'''
|
||||
"""forget(self): clears this TV, making all changes done through it permanent.
|
||||
Also, withdraws the TV from the stack."""
|
||||
self.state = S_EMPTY
|
||||
self.data = {}
|
||||
if self.is_in_stack:
|
||||
self.stack.withdraw(self)
|
||||
|
||||
def restore(self, ultimate = True):
|
||||
'''restore(ultimate = True): undoes all changes done through this tempovis / restores saved scene details.
|
||||
def restore(self, ultimate=True):
|
||||
"""restore(ultimate = True): undoes all changes done through this tempovis / restores saved scene details.
|
||||
ultimate: if true, the saved values are cleaned out, and the TV is withdrawn from
|
||||
the stack. If false, the TV will still remember stuff, and restore can be called again.
|
||||
'''
|
||||
"""
|
||||
if self.state == S_RESTORED:
|
||||
return
|
||||
|
||||
@@ -202,49 +211,59 @@ class TempoVis(object):
|
||||
try:
|
||||
self._restoreDetail(detail)
|
||||
except Exception as err:
|
||||
Err("TempoVis.restore: failed to restore detail {key}: {err}".format(key= key, err= str(err)))
|
||||
Err(
|
||||
"TempoVis.restore: failed to restore detail {key}: {err}".format(
|
||||
key=key, err=str(err)
|
||||
)
|
||||
)
|
||||
_printTraceback(err)
|
||||
if ultimate:
|
||||
self.data = {}
|
||||
if self.is_in_stack:
|
||||
self.stack.withdraw(self)
|
||||
|
||||
#</core interface>
|
||||
# </core interface>
|
||||
|
||||
#<stack interface>
|
||||
# <stack interface>
|
||||
def _inserted(self, stack, index):
|
||||
'''calles when this tv is inserted into a stack'''
|
||||
"""calles when this tv is inserted into a stack"""
|
||||
self.stack = stack
|
||||
|
||||
def _withdrawn(self, stack, index):
|
||||
'''calles when this tv is withdrawn from a stack'''
|
||||
"""calles when this tv is withdrawn from a stack"""
|
||||
self.stack = None
|
||||
|
||||
@property
|
||||
def is_in_stack(self):
|
||||
return self.stack is not None
|
||||
#</stack interface>
|
||||
|
||||
#<convenience functions>
|
||||
def modifyVPProperty(self, doc_obj_or_list, prop_names, new_value = JUST_SAVE, mild_restore = None):
|
||||
'''modifyVPProperty(doc_obj_or_list, prop_names, new_value = JUST_SAVE, mild_restore = None): modifies
|
||||
# </stack interface>
|
||||
|
||||
# <convenience functions>
|
||||
def modifyVPProperty(self, doc_obj_or_list, prop_names, new_value=JUST_SAVE, mild_restore=None):
|
||||
"""modifyVPProperty(doc_obj_or_list, prop_names, new_value = JUST_SAVE, mild_restore = None): modifies
|
||||
prop_name property of ViewProvider of doc_obj_or_list, and remembers
|
||||
original value of the property. Original values will be restored upon
|
||||
TempoVis deletion, or call to restore().
|
||||
|
||||
mild_restore: test if user changed the value manually when restoring the TV.'''
|
||||
mild_restore: test if user changed the value manually when restoring the TV."""
|
||||
|
||||
if self.state == S_RESTORED:
|
||||
Wrn("Attempting to use a TV that has been restored. There must be a problem with code.")
|
||||
return
|
||||
|
||||
if not hasattr(doc_obj_or_list, '__iter__'):
|
||||
if not hasattr(doc_obj_or_list, "__iter__"):
|
||||
doc_obj_or_list = [doc_obj_or_list]
|
||||
if not isinstance(prop_names,(list,tuple)):
|
||||
if not isinstance(prop_names, (list, tuple)):
|
||||
prop_names = [prop_names]
|
||||
for doc_obj in doc_obj_or_list:
|
||||
for prop_name in prop_names:
|
||||
if not hasattr(doc_obj.ViewObject, prop_name):
|
||||
Wrn("TempoVis: object {obj} has no attribute {attr}. Skipped."
|
||||
.format(obj= doc_obj.Name, attr= prop_name))
|
||||
Wrn(
|
||||
"TempoVis: object {obj} has no attribute {attr}. Skipped.".format(
|
||||
obj=doc_obj.Name, attr=prop_name
|
||||
)
|
||||
)
|
||||
continue
|
||||
|
||||
# Because the introduction of external objects, we shall now
|
||||
@@ -253,71 +272,80 @@ class TempoVis(object):
|
||||
# if doc_obj.Document is not self.document: #ignore objects from other documents
|
||||
# raise ValueError("Document object to be modified does not belong to document TempoVis was made for.")
|
||||
from .SceneDetails.VProperty import VProperty
|
||||
|
||||
if new_value is JUST_SAVE:
|
||||
if mild_restore:
|
||||
Wrn("TempoVis: can't just save a value for mild restore. Saving for hard restore.")
|
||||
Wrn(
|
||||
"TempoVis: can't just save a value for mild restore. Saving for hard restore."
|
||||
)
|
||||
self.save(VProperty(doc_obj, prop_name, new_value))
|
||||
else:
|
||||
self.modify(VProperty(doc_obj, prop_name, new_value), mild_restore)
|
||||
|
||||
def restoreVPProperty(self, doc_obj_or_list, prop_names):
|
||||
'''restoreVPProperty(doc_obj_or_list, prop_name, new_value): restores specific property changes.'''
|
||||
"""restoreVPProperty(doc_obj_or_list, prop_name, new_value): restores specific property changes."""
|
||||
from .SceneDetails.VProperty import VProperty
|
||||
|
||||
if not hasattr(doc_obj_or_list, '__iter__'):
|
||||
if not hasattr(doc_obj_or_list, "__iter__"):
|
||||
doc_obj_or_list = [doc_obj_or_list]
|
||||
if not isinstance(prop_names,(tuple,list)):
|
||||
if not isinstance(prop_names, (tuple, list)):
|
||||
prop_names = [prop_names]
|
||||
for doc_obj in doc_obj_or_list:
|
||||
for prop_name in prop_names:
|
||||
try:
|
||||
self.restoreDetail(VProperty(doc_obj, prop_name))
|
||||
except Exception as err:
|
||||
Err("TempoVis.restore: failed to restore detail {key}: {err}".format(key= key, err= str(err)))
|
||||
Err(
|
||||
"TempoVis.restore: failed to restore detail {key}: {err}".format(
|
||||
key=key, err=str(err)
|
||||
)
|
||||
)
|
||||
_printTraceback(err)
|
||||
|
||||
|
||||
def saveBodyVisibleFeature(self, doc_obj_or_list):
|
||||
"""saveBodyVisibleFeature(self, doc_obj_or_list): saves Visibility of currently
|
||||
visible feature, for every body of PartDesign features in the provided list."""
|
||||
if not hasattr(doc_obj_or_list, '__iter__'):
|
||||
if not hasattr(doc_obj_or_list, "__iter__"):
|
||||
doc_obj_or_list = [doc_obj_or_list]
|
||||
objs = []
|
||||
bodies = set()
|
||||
for obj in doc_obj_or_list:
|
||||
body = getattr(obj,'_Body',None)
|
||||
body = getattr(obj, "_Body", None)
|
||||
if not body or body in bodies:
|
||||
continue
|
||||
bodies.add(body)
|
||||
feature = getattr(body,'VisibleFeature',None)
|
||||
feature = getattr(body, "VisibleFeature", None)
|
||||
if feature:
|
||||
objs.append(feature)
|
||||
self.modifyVPProperty(objs, 'Visibility', JUST_SAVE)
|
||||
self.modifyVPProperty(objs, "Visibility", JUST_SAVE)
|
||||
return objs
|
||||
|
||||
def show(self, doc_obj_or_list, links_too = True, mild_restore = None):
|
||||
'''show(doc_obj_or_list, links_too = True): shows objects (sets their Visibility to True).
|
||||
def show(self, doc_obj_or_list, links_too=True, mild_restore=None):
|
||||
"""show(doc_obj_or_list, links_too = True): shows objects (sets their Visibility to True).
|
||||
doc_obj_or_list can be a document object, or a list of document objects.
|
||||
If links_too is True, all Links of the objects are also hidden, by setting LinkVisibility attribute of each object.'''
|
||||
If links_too is True, all Links of the objects are also hidden, by setting LinkVisibility attribute of each object."""
|
||||
doc_obj_or_list = self._3D_objects(doc_obj_or_list)
|
||||
self.saveBodyVisibleFeature(doc_obj_or_list) #fix implicit hiding of other features by PartDesign not being recorded to TV
|
||||
self.modifyVPProperty(doc_obj_or_list, 'Visibility', True, mild_restore)
|
||||
self.saveBodyVisibleFeature(
|
||||
doc_obj_or_list
|
||||
) # fix implicit hiding of other features by PartDesign not being recorded to TV
|
||||
self.modifyVPProperty(doc_obj_or_list, "Visibility", True, mild_restore)
|
||||
if links_too:
|
||||
self.modifyVPProperty(doc_obj_or_list, 'LinkVisibility', True, mild_restore)
|
||||
self.modifyVPProperty(doc_obj_or_list, "LinkVisibility", True, mild_restore)
|
||||
|
||||
def hide(self, doc_obj_or_list, links_too = True, mild_restore = None):
|
||||
'''hide(doc_obj_or_list): hides objects (sets their Visibility to False). doc_obj_or_list can be a document object, or a list of document objects'''
|
||||
def hide(self, doc_obj_or_list, links_too=True, mild_restore=None):
|
||||
"""hide(doc_obj_or_list): hides objects (sets their Visibility to False). doc_obj_or_list can be a document object, or a list of document objects"""
|
||||
doc_obj_or_list = self._3D_objects(doc_obj_or_list)
|
||||
# no need to saveBodyVisibleFeature here, as no implicit showing will happen
|
||||
self.modifyVPProperty(doc_obj_or_list, 'Visibility', False, mild_restore)
|
||||
self.modifyVPProperty(doc_obj_or_list, "Visibility", False, mild_restore)
|
||||
if links_too:
|
||||
self.modifyVPProperty(doc_obj_or_list, 'LinkVisibility', False, mild_restore)
|
||||
self.modifyVPProperty(doc_obj_or_list, "LinkVisibility", False, mild_restore)
|
||||
|
||||
def get_all_dependent(self, doc_obj, subname = None):
|
||||
'''get_all_dependent(doc_obj, subname = None): gets all objects that depend on doc_obj. Containers and Links (if subname) required for visibility of the object are excluded from the list.'''
|
||||
def get_all_dependent(self, doc_obj, subname=None):
|
||||
"""get_all_dependent(doc_obj, subname = None): gets all objects that depend on doc_obj. Containers and Links (if subname) required for visibility of the object are excluded from the list."""
|
||||
from . import Containers
|
||||
from .Containers import isAContainer
|
||||
from .DepGraphTools import getAllDependencies, getAllDependent
|
||||
|
||||
if subname:
|
||||
# a link-path was provided. doc_obj has nothing to do with the object we want
|
||||
# to collect dependencies from. So, replace it with the one pointed by link-path.
|
||||
@@ -329,48 +357,57 @@ class TempoVis(object):
|
||||
#
|
||||
# I don't know why do we need that isAContainer check here, but I'm leaving it,
|
||||
# realthunder must be knowing his business --DeepSOIC
|
||||
cnt_chain = [ o for o in cnt_chain
|
||||
if o==cnt_chain[-1] or isAContainer(o, links_too= True) ]
|
||||
cnt_chain = [
|
||||
o for o in cnt_chain if o == cnt_chain[-1] or isAContainer(o, links_too=True)
|
||||
]
|
||||
else:
|
||||
cnt_chain = Containers.ContainerChain(doc_obj)
|
||||
return [o for o in getAllDependent(doc_obj) if not o in cnt_chain]
|
||||
|
||||
def hide_all_dependent(self, doc_obj):
|
||||
'''hide_all_dependent(doc_obj): hides all objects that depend on doc_obj. Groups, Parts and Bodies are not hidden by this.'''
|
||||
"""hide_all_dependent(doc_obj): hides all objects that depend on doc_obj. Groups, Parts and Bodies are not hidden by this."""
|
||||
self.hide(self._3D_objects(self.get_all_dependent(doc_obj)))
|
||||
|
||||
def show_all_dependent(self, doc_obj):
|
||||
'''show_all_dependent(doc_obj): shows all objects that depend on doc_obj. This method is probably useless.'''
|
||||
"""show_all_dependent(doc_obj): shows all objects that depend on doc_obj. This method is probably useless."""
|
||||
from .DepGraphTools import getAllDependencies, getAllDependent
|
||||
|
||||
self.show(self._3D_objects(getAllDependent(doc_obj)))
|
||||
|
||||
def restore_all_dependent(self, doc_obj):
|
||||
'''show_all_dependent(doc_obj): restores original visibilities of all dependent objects.'''
|
||||
"""show_all_dependent(doc_obj): restores original visibilities of all dependent objects."""
|
||||
from .DepGraphTools import getAllDependencies, getAllDependent
|
||||
self.restoreVPProperty( getAllDependent(doc_obj), ('Visibility', 'LinkVisibility') )
|
||||
|
||||
self.restoreVPProperty(getAllDependent(doc_obj), ("Visibility", "LinkVisibility"))
|
||||
|
||||
def hide_all_dependencies(self, doc_obj):
|
||||
'''hide_all_dependencies(doc_obj): hides all objects that doc_obj depends on (directly and indirectly).'''
|
||||
"""hide_all_dependencies(doc_obj): hides all objects that doc_obj depends on (directly and indirectly)."""
|
||||
from .DepGraphTools import getAllDependencies, getAllDependent
|
||||
|
||||
self.hide(self._3D_objects(getAllDependencies(doc_obj)))
|
||||
|
||||
def show_all_dependencies(self, doc_obj):
|
||||
'''show_all_dependencies(doc_obj): shows all objects that doc_obj depends on (directly and indirectly). This method is probably useless.'''
|
||||
"""show_all_dependencies(doc_obj): shows all objects that doc_obj depends on (directly and indirectly). This method is probably useless."""
|
||||
from .DepGraphTools import getAllDependencies, getAllDependent
|
||||
|
||||
self.show(self._3D_objects(getAllDependencies(doc_obj)))
|
||||
|
||||
def saveCamera(self, vw = None):
|
||||
def saveCamera(self, vw=None):
|
||||
self._change()
|
||||
from .SceneDetails.Camera import Camera
|
||||
|
||||
self.save(Camera(self.document))
|
||||
|
||||
def restoreCamera(self, ultimate = False):
|
||||
def restoreCamera(self, ultimate=False):
|
||||
from .SceneDetails.Camera import Camera
|
||||
|
||||
dt = Camera(self.document)
|
||||
self.restoreDetail(dt, ultimate)
|
||||
|
||||
def setUnpickable(self, doc_obj_or_list, actual_pick_style = 2): #2 is coin.SoPickStyle.UNPICKABLE
|
||||
'''setUnpickable(doc_obj_or_list, actual_pick_style = 2): sets object unpickable (transparent to clicks).
|
||||
def setUnpickable(
|
||||
self, doc_obj_or_list, actual_pick_style=2
|
||||
): # 2 is coin.SoPickStyle.UNPICKABLE
|
||||
"""setUnpickable(doc_obj_or_list, actual_pick_style = 2): sets object unpickable (transparent to clicks).
|
||||
doc_obj_or_list: object or list of objects to alter (App)
|
||||
actual_pick_style: optional parameter, specifying the actual pick style:
|
||||
0 = regular, 1 = bounding box, 2 (default) = unpickable.
|
||||
@@ -378,12 +415,12 @@ class TempoVis(object):
|
||||
Implementation detail: uses SoPickStyle node. If viewprovider already has a node
|
||||
of this type as direct child, one is used. Otherwise, new one is created and
|
||||
inserted as the very first node, and remains there even after restore()/deleting
|
||||
tempovis. '''
|
||||
tempovis."""
|
||||
|
||||
from .SceneDetails.Pickability import Pickability
|
||||
from .ShowUtils import is3DObject
|
||||
|
||||
if not hasattr(doc_obj_or_list, '__iter__'):
|
||||
if not hasattr(doc_obj_or_list, "__iter__"):
|
||||
doc_obj_or_list = [doc_obj_or_list]
|
||||
for doc_obj in doc_obj_or_list:
|
||||
if not is3DObject(doc_obj):
|
||||
@@ -391,8 +428,8 @@ class TempoVis(object):
|
||||
dt = Pickability(doc_obj, actual_pick_style)
|
||||
self.modify(dt)
|
||||
|
||||
def clipPlane(self, doc_obj_or_list, enable, placement, offset = 0.02):
|
||||
'''clipPlane(doc_obj_or_list, enable, placement, offset): slices off the object with a clipping plane.
|
||||
def clipPlane(self, doc_obj_or_list, enable, placement, offset=0.02):
|
||||
"""clipPlane(doc_obj_or_list, enable, placement, offset): slices off the object with a clipping plane.
|
||||
doc_obj_or_list: object or list of objects to alter (App)
|
||||
enable: True if you want clipping, False if you want to remove clipping:
|
||||
placement: XY plane of local coordinates of the placement is the clipping plane. The placement must be in document's global coordinate system.
|
||||
@@ -400,12 +437,12 @@ class TempoVis(object):
|
||||
|
||||
Implementation detail: uses SoClipPlane node. If viewprovider already has a node
|
||||
of this type as direct child, one is used. Otherwise, new one is created and
|
||||
inserted as the very first node. The node is left, but disabled when tempovis is restoring.'''
|
||||
inserted as the very first node. The node is left, but disabled when tempovis is restoring."""
|
||||
|
||||
from .SceneDetails.ObjectClipPlane import ObjectClipPlane
|
||||
from .ShowUtils import is3DObject
|
||||
|
||||
if not hasattr(doc_obj_or_list, '__iter__'):
|
||||
if not hasattr(doc_obj_or_list, "__iter__"):
|
||||
doc_obj_or_list = [doc_obj_or_list]
|
||||
for doc_obj in doc_obj_or_list:
|
||||
if not is3DObject(doc_obj):
|
||||
@@ -415,8 +452,8 @@ class TempoVis(object):
|
||||
|
||||
@staticmethod
|
||||
def allVisibleObjects(aroundObject):
|
||||
'''allVisibleObjects(aroundObject): returns list of objects that have to be toggled invisible for only aroundObject to remain.
|
||||
If a whole container can be made invisible, it is returned, instead of its child objects.'''
|
||||
"""allVisibleObjects(aroundObject): returns list of objects that have to be toggled invisible for only aroundObject to remain.
|
||||
If a whole container can be made invisible, it is returned, instead of its child objects."""
|
||||
from .ShowUtils import is3DObject
|
||||
from . import Containers
|
||||
|
||||
@@ -424,7 +461,7 @@ class TempoVis(object):
|
||||
result = []
|
||||
for i in range(len(chain)):
|
||||
cnt = chain[i]
|
||||
cnt_next = chain[i+1] if i+1 < len(chain) else aroundObject
|
||||
cnt_next = chain[i + 1] if i + 1 < len(chain) else aroundObject
|
||||
container = Containers.Container(cnt)
|
||||
for obj in container.getVisGroupChildren():
|
||||
if not is3DObject(obj):
|
||||
@@ -434,9 +471,9 @@ class TempoVis(object):
|
||||
result.append(obj)
|
||||
return result
|
||||
|
||||
def sketchClipPlane(self, sketch, enable = None, reverted = False):
|
||||
'''sketchClipPlane(sketch, enable = None): Clips all objects by plane of sketch.
|
||||
If enable argument is omitted, calling the routine repeatedly will toggle clipping plane.'''
|
||||
def sketchClipPlane(self, sketch, enable=None, reverted=False):
|
||||
"""sketchClipPlane(sketch, enable = None): Clips all objects by plane of sketch.
|
||||
If enable argument is omitted, calling the routine repeatedly will toggle clipping plane."""
|
||||
|
||||
from .SceneDetails.ClipPlane import ClipPlane
|
||||
|
||||
@@ -452,32 +489,35 @@ class TempoVis(object):
|
||||
if reverted:
|
||||
pla = pla * App.Rotation(0, 1, 0, 0)
|
||||
|
||||
if enable: # clip plane shall be disabled so new placement can be applied
|
||||
if enable: # clip plane shall be disabled so new placement can be applied
|
||||
self.modify(ClipPlane(doc, 0))
|
||||
|
||||
self.modify(ClipPlane(doc, toggle, pla, 0.001))
|
||||
sketch.ViewObject.SectionView = enable if enable is not None else not sketch.ViewObject.SectionView
|
||||
sketch.ViewObject.SectionView = (
|
||||
enable if enable is not None else not sketch.ViewObject.SectionView
|
||||
)
|
||||
|
||||
def activateWorkbench(self, wb_name):
|
||||
from .SceneDetails.Workbench import Workbench
|
||||
|
||||
self.modify(Workbench(wb_name))
|
||||
|
||||
#</convenience functions>
|
||||
# </convenience functions>
|
||||
|
||||
#<internals>
|
||||
# <internals>
|
||||
def _restoreDetail(self, detail):
|
||||
p = self.data[detail.full_key]
|
||||
tv1, curr = self._value_after(detail, query_scene= p.mild_restore)
|
||||
tv1, curr = self._value_after(detail, query_scene=p.mild_restore)
|
||||
if p.mild_restore:
|
||||
if self.data_requested[detail.full_key] != curr:
|
||||
#the value on the scene doesn't match what was requested through TV. User probably changed it. We don't want to mess it up.
|
||||
# the value on the scene doesn't match what was requested through TV. User probably changed it. We don't want to mess it up.
|
||||
self._purge_milds(detail)
|
||||
return
|
||||
if tv1 is None:
|
||||
# no other TV has changed this detail later, apply to the scene
|
||||
detail.apply_data(p.data)
|
||||
else:
|
||||
#modify saved detail of higher TV
|
||||
# modify saved detail of higher TV
|
||||
tv1.data[detail.full_key].data = p.data
|
||||
|
||||
def _purge_milds(self, detail):
|
||||
@@ -490,23 +530,24 @@ class TempoVis(object):
|
||||
if tv.data[detail.full_key].mild_restore:
|
||||
tv.forgetDetail(detail)
|
||||
else:
|
||||
#hard-restoring value encountered, stop
|
||||
# hard-restoring value encountered, stop
|
||||
break
|
||||
|
||||
def _change(self):
|
||||
'''to be called whenever anything is done that is to be restored later.'''
|
||||
"""to be called whenever anything is done that is to be restored later."""
|
||||
if self.state == S_EMPTY:
|
||||
self.state = S_ACTIVE
|
||||
if self.state == S_RESTORED:
|
||||
Wrn("Attempting to use a TV that has been restored. There must be a problem with code.")
|
||||
self.tv_redo = None
|
||||
|
||||
def _value_after(self, detail, query_scene = False):
|
||||
'''_value_current(detail): returns (tv, detail1). SceneDetail instance holds "current" value of
|
||||
def _value_after(self, detail, query_scene=False):
|
||||
"""_value_current(detail): returns (tv, detail1). SceneDetail instance holds "current" value of
|
||||
scene detail (current from the context of this TV; i.e. either the current scene
|
||||
status, or the saved state from upper TVs).
|
||||
If no upper TV has saved the detail value, returns either (None, None), or
|
||||
(None, detail1) if query_scene is True, where detail1 holds value from the scene.'''
|
||||
(None, detail1) if query_scene is True, where detail1 holds value from the scene."""
|
||||
|
||||
def scene_value():
|
||||
if query_scene:
|
||||
cpy = copy(detail)
|
||||
@@ -528,7 +569,7 @@ class TempoVis(object):
|
||||
"""_3D_objects(doc_obj_or_list): returns list of objects that are in 3d view."""
|
||||
from .ShowUtils import is3DObject
|
||||
|
||||
if not hasattr(doc_obj_or_list, '__iter__'):
|
||||
if not hasattr(doc_obj_or_list, "__iter__"):
|
||||
doc_obj_or_list = [doc_obj_or_list]
|
||||
|
||||
return [obj for obj in doc_obj_or_list if is3DObject(obj)]
|
||||
|
||||
Reference in New Issue
Block a user