from typing import Optional import FreeCADGui as Gui import FreeCAD as App from PySide.QtCore import QTimer import random def _rgb(r, g, b): return r/255.0, g/255.0, b/255.0, 0.0 _colors = [ _rgb(94, 224, 174), _rgb(223, 234, 70), _rgb(35, 120, 200), _rgb(188, 80, 33), _rgb(26, 242, 69), _rgb(13, 41, 107), _rgb(153, 9, 52), _rgb(211, 119, 0), _rgb(34, 130, 7), _rgb(221, 79, 249) ] class AHB_Context: _activeStageId: int = None _allStagesVisible: bool = True _animationActive: bool = False _timeSinceLastStageUpdate: int = 0 def setActiveStage(self, stageId): self._activeStageId = stageId self._updateVisibility() def getActiveStage(self): return self._activeStageId def getAllStages(self): allStages = set() doc = App.ActiveDocument for obj in doc.Objects: if obj.TypeId in ['Part::Feature', 'App::Part']: if 'AssemblyHandbook_Stage' in obj.PropertiesList: allStages.add(obj.AssemblyHandbook_Stage) allStages = list(allStages) allStages.sort() return allStages def onPartStageChanged(self, part: Optional[App.DocumentObject]): allStages = self.getAllStages() doc = App.ActiveDocument if part is not None and not 'AssemblyHandbook_Stage' in part.PropertiesList: part.ViewObject.ShapeColor = (0.8,0.8,0.8,0.0) for obj in doc.Objects: if obj.TypeId in ['Part::Feature', 'App::Part']: if 'AssemblyHandbook_Stage' in obj.PropertiesList: stageIndex = allStages.index(obj.AssemblyHandbook_Stage) if obj.TypeId == 'Part::Feature': obj.ViewObject.ShapeColor = _colors[stageIndex % len(_colors)] elif obj.TypeId == 'App::Part': for feature in obj.Group: if feature.TypeId == 'Part::Feature': feature.ViewObject.ShapeColor = _colors[stageIndex % len(_colors)] self._updateVisibility() def setAllStagesVisible(self, allStagesVisible): self._allStagesVisible = allStagesVisible self._updateVisibility() def getAllStagesVisible(self): return self._allStagesVisible def _updateVisibility(self): activeStageId = self.getActiveStage() doc = App.ActiveDocument for obj in doc.Objects: if obj.TypeId == 'Part::Feature' in ['Part::Feature', 'App::Part']: if 'AssemblyHandbook_Stage' in obj.PropertiesList: obj.ViewObject.Visibility = self._allStagesVisible or activeStageId is None or obj.AssemblyHandbook_Stage <= activeStageId def setAnimationActive(self, animationActive): if self._animationActive == animationActive: return self._animationActive = animationActive self._updateAnimation() def getAnimationActive(self): return self._animationActive def _updateAnimation(self): if not self._animationActive: return allStages = self.getAllStages() if len(allStages) > 1 and self._timeSinceLastStageUpdate >= 1000: self._timeSinceLastStageUpdate = 0 activeStageId = self.getActiveStage() or 0 stageIndex = allStages.index(activeStageId) if activeStageId in allStages else 0 stageIndex = (stageIndex + 1) % len(allStages) self.setActiveStage(allStages[stageIndex]) tickResolution = 33 import math from pivy import coin cam = Gui.ActiveDocument.ActiveView.getCameraNode() """rot = coin.SbRotation() rot.setValue(coin.SbVec3f(0, 0, 1), math.pi * tickResolution / 1000.0) nrot = cam.orientation.getValue() * rot cam.orientation = nrot""" center = coin.SbVec3f(1000,0,750) v = cam.position.getValue() - center v[2] = 0 dist = v.length() height = cam.position.getValue()[2] angle = math.atan2(v[1], v[0]) angle = angle + 0.3 * tickResolution / 1000.0 cam.position = coin.SbVec3f(center[0] + math.cos(angle)*dist, center[1] + math.sin(angle)*dist, height) cam.pointAt(center, coin.SbVec3f(0,0,1)) self._timeSinceLastStageUpdate = self._timeSinceLastStageUpdate + tickResolution QTimer.singleShot(tickResolution, self._updateAnimation)