forked from youen/assembly_handbook
Added possibility to annotate parts of sub-assemblies
This commit is contained in:
parent
d7f520805d
commit
d6fb938d96
@ -1,4 +1,5 @@
|
||||
sys.path.append('/usr/local/lib/python3.9/dist-packages/')
|
||||
#sys.path.append('/usr/local/lib/python3.9/dist-packages/')
|
||||
sys.path.append('/home/youen/.FreeCAD/Mod/assembly_handbook/pydev')
|
||||
#import pydevd
|
||||
#pydevd.settrace()
|
||||
|
||||
@ -89,6 +90,9 @@ class AssemblyHandbookWorkbench(Gui.Workbench):
|
||||
self.importModule('ahb_cmd_view_annotate')
|
||||
toolbox.append("AHB_view_annotate")
|
||||
|
||||
self.importModule('ahb_cmd_view_annotate_detail')
|
||||
toolbox.append('AHB_view_annotate_detail')
|
||||
|
||||
self.importModule('ahb_cmd_view_edit_source_parts')
|
||||
toolbox.append("AHB_view_edit_source_parts")
|
||||
toolbox.append("AHB_view_add_source_parts")
|
||||
|
@ -29,12 +29,27 @@ class AHB_View_Annotate:
|
||||
if page is None:
|
||||
raise Exception("Can't find page in which the selected view is located")
|
||||
|
||||
def list_sub_parts(parts):
|
||||
result = []
|
||||
for part in parts:
|
||||
if part.TypeId == 'App::Link':
|
||||
result.append(part)
|
||||
elif part.TypeId == 'Part::FeaturePython' and hasattr(part, 'LinkedObject'): # variant link
|
||||
result.append(part)
|
||||
|
||||
if hasattr(part, 'Group'):
|
||||
result.extend(list_sub_parts(part.Group))
|
||||
|
||||
return result
|
||||
|
||||
all_parts = list_sub_parts(view.XSource)
|
||||
|
||||
# Remove balloons referencing missing objects
|
||||
for balloon in page.Views:
|
||||
if balloon.TypeId == 'TechDraw::DrawViewBalloon' and "Assembly_handbook_Source" in balloon.PropertiesList:
|
||||
if balloon.SourceView != view and balloon.SourceView != overlay_view: continue
|
||||
partLink = workbench.techDrawExtensions.getBalloonSourcePart(balloon)
|
||||
if partLink is None or partLink not in view.XSource:
|
||||
if partLink is None or partLink not in all_parts:
|
||||
ref_name = "<no ref>"
|
||||
try:
|
||||
ref_name = balloon.Assembly_handbook_Source[1]
|
||||
@ -44,41 +59,7 @@ class AHB_View_Annotate:
|
||||
doc.removeObject(balloon.Name)
|
||||
|
||||
for partLink in view.XSource:
|
||||
balloon = None
|
||||
|
||||
# Search an existing balloon to update
|
||||
for obj in page.Views:
|
||||
if obj.TypeId == 'TechDraw::DrawViewBalloon' and workbench.techDrawExtensions.getBalloonSourcePart(obj) == partLink:
|
||||
if obj.SourceView != overlay_view: continue
|
||||
balloon = obj
|
||||
|
||||
# Create a new balloon if needed
|
||||
if balloon is None:
|
||||
if workbench.techDrawExtensions.isNewPartInView(view, partLink):
|
||||
partName = partLink.Name
|
||||
|
||||
balloonName = partName + "_Balloon"
|
||||
|
||||
balloon = doc.addObject("TechDraw::DrawViewBalloon", balloonName)
|
||||
balloon.SourceView = overlay_view
|
||||
|
||||
balloon.addProperty("App::PropertyXLink", "Assembly_handbook_Source", "Assembly_handbook")
|
||||
balloon.Assembly_handbook_Source = (partLink, partLink.Name)
|
||||
|
||||
balloon.addProperty("App::PropertyFloat", "Assembly_handbook_OriginOffsetX", "Assembly_handbook")
|
||||
balloon.addProperty("App::PropertyFloat", "Assembly_handbook_OriginOffsetY", "Assembly_handbook")
|
||||
|
||||
page.addView(balloon)
|
||||
|
||||
workbench.techDrawExtensions.updateBalloon(balloon)
|
||||
|
||||
balloon.X = int(balloon.OriginX) + 20
|
||||
balloon.Y = int(balloon.OriginY) + 20
|
||||
|
||||
if not workbench.techDrawExtensions.isNewPartInView(view, partLink):
|
||||
balloon.ViewObject.Visibility = False
|
||||
else:
|
||||
workbench.techDrawExtensions.updateBalloon(balloon)
|
||||
workbench.techDrawExtensions.add_or_update_balloon(view, partLink, '')
|
||||
|
||||
from ahb_command import AHB_CommandWrapper
|
||||
AHB_CommandWrapper.addGuiCommand('AHB_view_annotate', AHB_View_Annotate())
|
||||
|
60
ahb_cmd_view_annotate_detail.py
Normal file
60
ahb_cmd_view_annotate_detail.py
Normal file
@ -0,0 +1,60 @@
|
||||
import FreeCADGui as Gui
|
||||
import FreeCAD as App
|
||||
|
||||
class AHB_View_Annotate_Detail:
|
||||
def GetResources(self):
|
||||
return {"MenuText": "Add annotation details",
|
||||
"ToolTip": "Annotates each part of a sub-assembly",
|
||||
"Pixmap": ""
|
||||
}
|
||||
|
||||
def IsActive(self):
|
||||
return True
|
||||
|
||||
def Activated(self):
|
||||
workbench = Gui.getWorkbench("AssemblyHandbookWorkbench") #: :type workbench: AssemblyHandbookWorkbench
|
||||
|
||||
if len(Gui.Selection.getSelection()) == 0:
|
||||
raise Exception("Please select at least one annotation balloon")
|
||||
|
||||
view = None
|
||||
for balloon in Gui.Selection.getSelection():
|
||||
if balloon.TypeId != 'TechDraw::DrawViewBalloon' or "Assembly_handbook_Source" not in balloon.PropertiesList:
|
||||
raise Exception("All selected objects must be annotation balloons")
|
||||
if view is not None and view != balloon.SourceView or balloon.SourceView is None:
|
||||
raise Exception("Please only select balloons from the same view")
|
||||
view = balloon.SourceView
|
||||
|
||||
overlay_view = workbench.techDrawExtensions.getOverlayView(view)
|
||||
|
||||
doc = view.Document
|
||||
|
||||
page = workbench.techDrawExtensions.getViewPage(view)
|
||||
if page is None:
|
||||
raise Exception("Can't find page in which the selected view is located")
|
||||
|
||||
balloons_to_split = Gui.Selection.getSelection()
|
||||
|
||||
for balloon in balloons_to_split:
|
||||
sub_assembly_link = workbench.techDrawExtensions.getBalloonSourcePart(balloon)
|
||||
sub_assembly = sub_assembly_link.LinkedObject
|
||||
if sub_assembly.TypeId != 'App::Part': continue
|
||||
|
||||
def list_first_level_sub_parts(group):
|
||||
results = []
|
||||
for obj in group.Group:
|
||||
if obj.TypeId == 'App::Link':
|
||||
results.append(obj)
|
||||
elif obj.TypeId == 'Part::FeaturePython' and hasattr(obj, 'LinkedObject'): # variant link
|
||||
results.append(obj)
|
||||
elif hasattr(obj, 'Group'):
|
||||
results.extend(list_first_level_sub_parts(obj))
|
||||
return results
|
||||
|
||||
parts = list_first_level_sub_parts(sub_assembly)
|
||||
|
||||
for part in parts:
|
||||
workbench.techDrawExtensions.add_or_update_balloon(view, part, workbench.techDrawExtensions.getBalloonSourcePartPath(balloon))
|
||||
|
||||
from ahb_command import AHB_CommandWrapper
|
||||
AHB_CommandWrapper.addGuiCommand('AHB_view_annotate_detail', AHB_View_Annotate_Detail())
|
@ -431,7 +431,7 @@ class TechDrawExtensions:
|
||||
|
||||
obj = self.getBalloonSourcePart(balloon)
|
||||
view = balloon.SourceView
|
||||
center = self.computePartCenter(view, obj)
|
||||
center = self.computePartCenter(view, obj, self.getBalloonSourcePartPath(balloon))
|
||||
|
||||
balloon.Assembly_handbook_OriginOffsetX = new_pos.x - center.x
|
||||
balloon.Assembly_handbook_OriginOffsetY = new_pos.y - center.y
|
||||
@ -456,15 +456,66 @@ class TechDrawExtensions:
|
||||
self.updateBalloon(obj)
|
||||
self.updating_balloon = False
|
||||
|
||||
def add_or_update_balloon(self, view, part, parent_path):
|
||||
page = self.getViewPage(view)
|
||||
overlay_view = self.getOverlayView(view)
|
||||
doc = page.Document
|
||||
|
||||
path = parent_path
|
||||
if path == '':
|
||||
path = part.Document.Name + '#' + part.Name
|
||||
else:
|
||||
path += '.'
|
||||
path += part.Name
|
||||
|
||||
# Search an existing balloon to update
|
||||
balloon = None
|
||||
for obj in page.Views:
|
||||
if obj.TypeId == 'TechDraw::DrawViewBalloon' and self.getBalloonSourcePart(obj) == part and self.getBalloonSourcePartPath(obj) == path:
|
||||
if obj.SourceView != overlay_view: continue
|
||||
balloon = obj
|
||||
|
||||
# Create a new balloon if needed
|
||||
if balloon is None:
|
||||
if self.isNewPartInView(view, part):
|
||||
partName = part.Name
|
||||
|
||||
balloonName = partName + "_Balloon"
|
||||
|
||||
balloon = doc.addObject("TechDraw::DrawViewBalloon", balloonName)
|
||||
balloon.SourceView = overlay_view
|
||||
|
||||
balloon.addProperty("App::PropertyXLink", "Assembly_handbook_Source", "Assembly_handbook")
|
||||
balloon.Assembly_handbook_Source = (part, part.Name)
|
||||
|
||||
balloon.addProperty("App::PropertyString", "Assembly_handbook_SourcePath", "Assembly_handbook")
|
||||
balloon.Assembly_handbook_SourcePath = path
|
||||
|
||||
balloon.addProperty("App::PropertyFloat", "Assembly_handbook_OriginOffsetX", "Assembly_handbook")
|
||||
balloon.addProperty("App::PropertyFloat", "Assembly_handbook_OriginOffsetY", "Assembly_handbook")
|
||||
|
||||
page.addView(balloon)
|
||||
|
||||
self.updateBalloon(balloon)
|
||||
|
||||
balloon.X = int(balloon.OriginX) + 20
|
||||
balloon.Y = int(balloon.OriginY) + 20
|
||||
|
||||
if not self.isNewPartInView(view, part):
|
||||
balloon.ViewObject.Visibility = False
|
||||
else:
|
||||
self.updateBalloon(balloon)
|
||||
|
||||
def updateBalloon(self, balloon):
|
||||
workbench = Gui.getWorkbench("AssemblyHandbookWorkbench") #: :type workbench: AssemblyHandbookWorkbench
|
||||
|
||||
view = balloon.SourceView
|
||||
obj = self.getBalloonSourcePart(balloon)
|
||||
path = self.getBalloonSourcePartPath(balloon)
|
||||
|
||||
partDisplayName = 'Inconnu' if obj is None else self.getPartDisplayName(obj)
|
||||
|
||||
objectCenterView = workbench.techDrawExtensions.computePartCenter(view, obj)
|
||||
objectCenterView = workbench.techDrawExtensions.computePartCenter(view, obj, path)
|
||||
|
||||
balloon.OriginX = objectCenterView.x + balloon.Assembly_handbook_OriginOffsetX
|
||||
balloon.OriginY = objectCenterView.y + balloon.Assembly_handbook_OriginOffsetY
|
||||
@ -481,6 +532,15 @@ class TechDrawExtensions:
|
||||
except:
|
||||
return None
|
||||
|
||||
def getBalloonSourcePartPath(self, balloon):
|
||||
try:
|
||||
return balloon.Assembly_handbook_SourcePath
|
||||
except:
|
||||
part = self.getBalloonSourcePart(balloon)
|
||||
if part is None:
|
||||
return ''
|
||||
return part.Document.Name + '#' + part.Name
|
||||
|
||||
def isPartLink(self, obj):
|
||||
if obj.TypeId == 'App::Link':
|
||||
return True
|
||||
@ -584,18 +644,40 @@ class TechDrawExtensions:
|
||||
overlay = view.Document.getObject(view.Name + '_overlay')
|
||||
return overlay if overlay is not None else view
|
||||
|
||||
def computePartCenter(self, view, obj):
|
||||
def computePartCenter(self, view, obj, path = None):
|
||||
view = self.getSourceView(view)
|
||||
|
||||
mat = App.Matrix()
|
||||
|
||||
if path is not None:
|
||||
path_parts = path.split('.')
|
||||
path_parts.pop()
|
||||
|
||||
parent = None
|
||||
for part in path_parts:
|
||||
if parent is None:
|
||||
doc_obj = part.split('#')
|
||||
doc = App.getDocument(doc_obj[0])
|
||||
link = doc.getObject(doc_obj[1])
|
||||
else:
|
||||
link = parent.Document.getObject(part)
|
||||
|
||||
mat = link.LinkPlacement * mat
|
||||
parent = link.LinkedObject
|
||||
|
||||
if obj.TypeId == 'App::Link':
|
||||
partLink = obj
|
||||
objectCenterWorld = partLink.LinkPlacement.Matrix.multiply(partLink.LinkedObject.Shape.CenterOfGravity)
|
||||
mat = mat.multiply(partLink.LinkPlacement.Matrix)
|
||||
objectCenterWorld = partLink.LinkedObject.Shape.CenterOfGravity
|
||||
elif obj.TypeId == 'Part::FeaturePython' and hasattr(obj, 'LinkedObject'): # variant link
|
||||
partLink = obj
|
||||
objectCenterWorld = partLink.Placement.Matrix.multiply(partLink.LinkedObject.Shape.CenterOfGravity)
|
||||
mat = mat.multiply(partLink.Placement.Matrix)
|
||||
objectCenterWorld = partLink.LinkedObject.Shape.CenterOfGravity
|
||||
else:
|
||||
objectCenterWorld = obj.Shape.CenterOfGravity
|
||||
|
||||
objectCenterWorld = mat.multiply(objectCenterWorld)
|
||||
|
||||
'''view_cache = self.getViewCache(view)
|
||||
|
||||
key = (objectCenterWorld.x, objectCenterWorld.y, objectCenterWorld.z)
|
||||
|
Loading…
Reference in New Issue
Block a user