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
|
#import pydevd
|
||||||
#pydevd.settrace()
|
#pydevd.settrace()
|
||||||
|
|
||||||
@ -89,6 +90,9 @@ class AssemblyHandbookWorkbench(Gui.Workbench):
|
|||||||
self.importModule('ahb_cmd_view_annotate')
|
self.importModule('ahb_cmd_view_annotate')
|
||||||
toolbox.append("AHB_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')
|
self.importModule('ahb_cmd_view_edit_source_parts')
|
||||||
toolbox.append("AHB_view_edit_source_parts")
|
toolbox.append("AHB_view_edit_source_parts")
|
||||||
toolbox.append("AHB_view_add_source_parts")
|
toolbox.append("AHB_view_add_source_parts")
|
||||||
|
@ -29,12 +29,27 @@ class AHB_View_Annotate:
|
|||||||
if page is None:
|
if page is None:
|
||||||
raise Exception("Can't find page in which the selected view is located")
|
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
|
# Remove balloons referencing missing objects
|
||||||
for balloon in page.Views:
|
for balloon in page.Views:
|
||||||
if balloon.TypeId == 'TechDraw::DrawViewBalloon' and "Assembly_handbook_Source" in balloon.PropertiesList:
|
if balloon.TypeId == 'TechDraw::DrawViewBalloon' and "Assembly_handbook_Source" in balloon.PropertiesList:
|
||||||
if balloon.SourceView != view and balloon.SourceView != overlay_view: continue
|
if balloon.SourceView != view and balloon.SourceView != overlay_view: continue
|
||||||
partLink = workbench.techDrawExtensions.getBalloonSourcePart(balloon)
|
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>"
|
ref_name = "<no ref>"
|
||||||
try:
|
try:
|
||||||
ref_name = balloon.Assembly_handbook_Source[1]
|
ref_name = balloon.Assembly_handbook_Source[1]
|
||||||
@ -44,41 +59,7 @@ class AHB_View_Annotate:
|
|||||||
doc.removeObject(balloon.Name)
|
doc.removeObject(balloon.Name)
|
||||||
|
|
||||||
for partLink in view.XSource:
|
for partLink in view.XSource:
|
||||||
balloon = None
|
workbench.techDrawExtensions.add_or_update_balloon(view, partLink, '')
|
||||||
|
|
||||||
# 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)
|
|
||||||
|
|
||||||
from ahb_command import AHB_CommandWrapper
|
from ahb_command import AHB_CommandWrapper
|
||||||
AHB_CommandWrapper.addGuiCommand('AHB_view_annotate', AHB_View_Annotate())
|
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)
|
obj = self.getBalloonSourcePart(balloon)
|
||||||
view = balloon.SourceView
|
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_OriginOffsetX = new_pos.x - center.x
|
||||||
balloon.Assembly_handbook_OriginOffsetY = new_pos.y - center.y
|
balloon.Assembly_handbook_OriginOffsetY = new_pos.y - center.y
|
||||||
@ -456,15 +456,66 @@ class TechDrawExtensions:
|
|||||||
self.updateBalloon(obj)
|
self.updateBalloon(obj)
|
||||||
self.updating_balloon = False
|
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):
|
def updateBalloon(self, balloon):
|
||||||
workbench = Gui.getWorkbench("AssemblyHandbookWorkbench") #: :type workbench: AssemblyHandbookWorkbench
|
workbench = Gui.getWorkbench("AssemblyHandbookWorkbench") #: :type workbench: AssemblyHandbookWorkbench
|
||||||
|
|
||||||
view = balloon.SourceView
|
view = balloon.SourceView
|
||||||
obj = self.getBalloonSourcePart(balloon)
|
obj = self.getBalloonSourcePart(balloon)
|
||||||
|
path = self.getBalloonSourcePartPath(balloon)
|
||||||
|
|
||||||
partDisplayName = 'Inconnu' if obj is None else self.getPartDisplayName(obj)
|
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.OriginX = objectCenterView.x + balloon.Assembly_handbook_OriginOffsetX
|
||||||
balloon.OriginY = objectCenterView.y + balloon.Assembly_handbook_OriginOffsetY
|
balloon.OriginY = objectCenterView.y + balloon.Assembly_handbook_OriginOffsetY
|
||||||
@ -481,6 +532,15 @@ class TechDrawExtensions:
|
|||||||
except:
|
except:
|
||||||
return None
|
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):
|
def isPartLink(self, obj):
|
||||||
if obj.TypeId == 'App::Link':
|
if obj.TypeId == 'App::Link':
|
||||||
return True
|
return True
|
||||||
@ -584,18 +644,40 @@ class TechDrawExtensions:
|
|||||||
overlay = view.Document.getObject(view.Name + '_overlay')
|
overlay = view.Document.getObject(view.Name + '_overlay')
|
||||||
return overlay if overlay is not None else view
|
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)
|
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':
|
if obj.TypeId == 'App::Link':
|
||||||
partLink = obj
|
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
|
elif obj.TypeId == 'Part::FeaturePython' and hasattr(obj, 'LinkedObject'): # variant link
|
||||||
partLink = obj
|
partLink = obj
|
||||||
objectCenterWorld = partLink.Placement.Matrix.multiply(partLink.LinkedObject.Shape.CenterOfGravity)
|
mat = mat.multiply(partLink.Placement.Matrix)
|
||||||
|
objectCenterWorld = partLink.LinkedObject.Shape.CenterOfGravity
|
||||||
else:
|
else:
|
||||||
objectCenterWorld = obj.Shape.CenterOfGravity
|
objectCenterWorld = obj.Shape.CenterOfGravity
|
||||||
|
|
||||||
|
objectCenterWorld = mat.multiply(objectCenterWorld)
|
||||||
|
|
||||||
'''view_cache = self.getViewCache(view)
|
'''view_cache = self.getViewCache(view)
|
||||||
|
|
||||||
key = (objectCenterWorld.x, objectCenterWorld.y, objectCenterWorld.z)
|
key = (objectCenterWorld.x, objectCenterWorld.y, objectCenterWorld.z)
|
||||||
|
Loading…
Reference in New Issue
Block a user