Show: Tempovis stack support

Improvents:
* Allows using several tempovis instances in arbitrary order
* plugin system (SceneDetail), ease of extending
* Mild restore feature - more respect for changes made by user
* workbench switching support
* undo saveable changes for the time of writing a file

Regressions:
* Removed support for pickling (with hopes to reintroduce later)
This commit is contained in:
DeepSOIC
2019-08-24 02:23:39 +03:00
committed by Yorik van Havre
parent 7969979686
commit 6dcdc7fe22
15 changed files with 1144 additions and 362 deletions

View File

@@ -0,0 +1,48 @@
#/***************************************************************************
# * Copyright (c) Victor Titov (DeepSOIC) *
# * (vv.titov@gmail.com) 2019 *
# * *
# * This file is part of the FreeCAD CAx development system. *
# * *
# * This library is free software; you can redistribute it and/or *
# * modify it under the terms of the GNU Library General Public *
# * License as published by the Free Software Foundation; either *
# * version 2 of the License, or (at your option) any later version. *
# * *
# * This library is distributed in the hope that it will be useful, *
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
# * GNU Library General Public License for more details. *
# * *
# * You should have received a copy of the GNU Library General Public *
# * License along with this library; see the file COPYING.LIB. If not, *
# * write to the Free Software Foundation, Inc., 59 Temple Place, *
# * Suite 330, Boston, MA 02111-1307, USA *
# * *
# ***************************************************************************/
from Show.SceneDetail import SceneDetail
import FreeCADGui
class Camera(SceneDetail):
"""Camera(doc): TempoVis plugin for saving and restoring camera."""
class_id = 'SDCamera'
def __init__(self, doc):
self.doc = doc
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]
return v
def scene_value(self):
return self._viewer().getCamera()
def apply_data(self, val):
self._viewer().setCamera(val)

View File

@@ -0,0 +1,64 @@
#/***************************************************************************
# * Copyright (c) Victor Titov (DeepSOIC) *
# * (vv.titov@gmail.com) 2019 *
# * *
# * This file is part of the FreeCAD CAx development system. *
# * *
# * This library is free software; you can redistribute it and/or *
# * modify it under the terms of the GNU Library General Public *
# * License as published by the Free Software Foundation; either *
# * version 2 of the License, or (at your option) any later version. *
# * *
# * This library is distributed in the hope that it will be useful, *
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
# * GNU Library General Public License for more details. *
# * *
# * You should have received a copy of the GNU Library General Public *
# * License along with this library; see the file COPYING.LIB. If not, *
# * write to the Free Software Foundation, Inc., 59 Temple Place, *
# * Suite 330, Boston, MA 02111-1307, USA *
# * *
# ***************************************************************************/
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 = ''
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.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.
def apply_data(self, val):
enable, pla = val
if enable != 0:
self._viewer().toggleClippingPlane(enable, pla= pla)
else:
self._viewer().toggleClippingPlane(enable)
def _viewer(self):
if self.doc is None:
gdoc = Gui.editDocument()
else:
gdoc = Gui.getDocument(self.doc.Name)
v = gdoc.activeView()
if not hasattr(v, 'toggleClippingPlane'):
v = gdoc.mdiViewsOfType('Gui::View3DInventor')[0]
return v

View File

@@ -0,0 +1,107 @@
#/***************************************************************************
# * Copyright (c) Victor Titov (DeepSOIC) *
# * (vv.titov@gmail.com) 2019 *
# * *
# * This file is part of the FreeCAD CAx development system. *
# * *
# * This library is free software; you can redistribute it and/or *
# * modify it under the terms of the GNU Library General Public *
# * License as published by the Free Software Foundation; either *
# * version 2 of the License, or (at your option) any later version. *
# * *
# * This library is distributed in the hope that it will be useful, *
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
# * GNU Library General Public License for more details. *
# * *
# * You should have received a copy of the GNU Library General Public *
# * License along with this library; see the file COPYING.LIB. If not, *
# * write to the Free Software Foundation, Inc., 59 Temple Place, *
# * Suite 330, Boston, MA 02111-1307, USA *
# * *
# ***************************************************************************/
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):
self.objname = object.Name
self.doc = object.Document
self.key = self.objname
if enable is not None:
self.data = self.val(enable, placement, offset)
def scene_value(self):
vp = self.doc.getObject(self.objname).ViewObject
cp = getClipPlaneNode(vp, make_if_missing= False)
if cp is None:
return self.val(False)
else:
enable = cp.on.getValue()
pln = cp.plane
D = pln.getDistanceFromOrigin()
normal = tuple(pln.getNormal())
return enable, (normal, D)
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)
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):
"""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."""
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_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):
from pivy import coin
sa = coin.SoSearchAction()
sa.setType(coin.SoClipPlane.getClassTypeId())
sa.setName('TVClipPlane')
sa.traverse(viewprovider.RootNode)
if sa.isFound() and sa.getPath().getLength() == 1:
return sa.getPath().getTail()
elif not sa.isFound():
if not make_if_missing:
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
return clipplane
def placement2plane(placement, offset):
"""returns tuple (normal, D) for making coin plane."""
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):
if tv is None:
from Show.TempoVis import TempoVis
tv = TempoVis(obj.Document)
tv.modify(ClipPlane(obj, enable, placement, offset))
return tv

View File

@@ -0,0 +1,81 @@
#/***************************************************************************
# * Copyright (c) Victor Titov (DeepSOIC) *
# * (vv.titov@gmail.com) 2019 *
# * *
# * This file is part of the FreeCAD CAx development system. *
# * *
# * This library is free software; you can redistribute it and/or *
# * modify it under the terms of the GNU Library General Public *
# * License as published by the Free Software Foundation; either *
# * version 2 of the License, or (at your option) any later version. *
# * *
# * This library is distributed in the hope that it will be useful, *
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
# * GNU Library General Public License for more details. *
# * *
# * You should have received a copy of the GNU Library General Public *
# * License along with this library; see the file COPYING.LIB. If not, *
# * write to the Free Software Foundation, Inc., 59 Temple Place, *
# * Suite 330, Boston, MA 02111-1307, USA *
# * *
# ***************************************************************************/
from Show.SceneDetail import SceneDetail
class Pickability(SceneDetail):
"""Pickability(object, pickstyle = None):Plugin for TempoVis for altering pick style
of objects (i.e., selectability).
pickstyle may be:
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):
self.objname = object.Name
self.doc = object.Document
self.key = self.objname
if pickstyle is not None:
self.data = pickstyle
def scene_value(self):
return getPickStyle(self.doc.getObject(self.objname).ViewObject)
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):
from pivy import coin
sa = coin.SoSearchAction()
sa.setType(coin.SoPickStyle.getClassTypeId())
sa.traverse(viewprovider.RootNode)
if sa.isFound() and sa.getPath().getLength() == 1:
return sa.getPath().getTail()
else:
if not make_if_missing:
return None
pick_style = coin.SoPickStyle()
pick_style.style.setValue(coin.SoPickStyle.SHAPE)
viewprovider.RootNode.insertChild(pick_style, 0)
return pick_style
def getPickStyle(viewprovider):
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
if ps is not None:
return ps.style.setValue(pickstyle)

View File

@@ -0,0 +1,48 @@
#/***************************************************************************
# * Copyright (c) Victor Titov (DeepSOIC) *
# * (vv.titov@gmail.com) 2019 *
# * *
# * This file is part of the FreeCAD CAx development system. *
# * *
# * This library is free software; you can redistribute it and/or *
# * modify it under the terms of the GNU Library General Public *
# * License as published by the Free Software Foundation; either *
# * version 2 of the License, or (at your option) any later version. *
# * *
# * This library is distributed in the hope that it will be useful, *
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
# * GNU Library General Public License for more details. *
# * *
# * You should have received a copy of the GNU Library General Public *
# * License along with this library; see the file COPYING.LIB. If not, *
# * write to the Free Software Foundation, Inc., 59 Temple Place, *
# * Suite 330, Boston, MA 02111-1307, USA *
# * *
# ***************************************************************************/
from Show.SceneDetail import SceneDetail
class VProperty(SceneDetail):
"""VProperty(object, propname, val = None): plugin for TempoVis to alter ViewProvider properties"""
class_id = 'SDVProperty'
affects_persistence = True
propname = ''
objname = ''
mild_restore = True
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.data = val
if propname == 'LinkVisibility': #seems to not be a property
self.affects_persistence = False
def scene_value(self):
return getattr(self.doc.getObject(self.objname).ViewObject, self.propname)
def apply_data(self, val):
setattr(self.doc.getObject(self.objname).ViewObject, self.propname, val)

View File

@@ -0,0 +1,44 @@
#/***************************************************************************
# * Copyright (c) Victor Titov (DeepSOIC) *
# * (vv.titov@gmail.com) 2019 *
# * *
# * This file is part of the FreeCAD CAx development system. *
# * *
# * This library is free software; you can redistribute it and/or *
# * modify it under the terms of the GNU Library General Public *
# * License as published by the Free Software Foundation; either *
# * version 2 of the License, or (at your option) any later version. *
# * *
# * This library is distributed in the hope that it will be useful, *
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
# * GNU Library General Public License for more details. *
# * *
# * You should have received a copy of the GNU Library General Public *
# * License along with this library; see the file COPYING.LIB. If not, *
# * write to the Free Software Foundation, Inc., 59 Temple Place, *
# * Suite 330, Boston, MA 02111-1307, USA *
# * *
# ***************************************************************************/
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'
mild_restore = True
def __init__(self, wb = None):
self.key = 'workbench'
if wb is not None:
self.data = wb
def scene_value(self):
return FreeCADGui.activeWorkbench().name()
def apply_data(self, val):
FreeCADGui.activateWorkbench(val)

View File