@ -7,6 +7,8 @@ import TechDraw, TechDrawGui
from PySide import QtGui , QtCore
TDG = TechDrawGui
from ahb_material import Material
class CursorItem ( QtGui . QGraphicsItem ) :
def __init__ ( self , parent = None , view = None ) :
super ( ) . __init__ ( parent )
@ -16,6 +18,9 @@ class CursorItem(QtGui.QGraphicsItem):
self . size = 100.0
self . view = view
def removeSceneEventFilter ( self , a , b ) :
print ( ' removeSceneEventFilter ' , a , b )
def onViewPosChange ( self , callback ) :
self . viewPosChangeCallback = callback
@ -74,133 +79,230 @@ class TechDrawExtensions:
enable_selected_part_highlight = False # disable for now, for performance reasons
initialized_documents = [ ]
def __init__ ( self ) :
workbench = Gui . getWorkbench ( " AssemblyHandbookWorkbench " ) #: :type workbench: AssemblyHandbookWorkbench
workbench . docObserver . onObjectTypeChanged ( ' balloon_changed ' , ' TechDraw::DrawViewBalloon ' , lambda obj , prop : self . onBalloonChanged ( obj , prop ) )
workbench . docObserver . onObjectTypeSelected ( ' balloon_selected ' , ' TechDraw::DrawViewBalloon ' , lambda operation , obj , sub , point : self . onBalloonSelected ( operation , obj , sub , point ) )
workbench . docObserver . onDocumentEvent ( ' techdrawext_doc_event ' , lambda doc , event : self . onDocumentEvent ( doc , event ) )
if App . ActiveDocument is not None :
self . onDocumentEvent ( App . ActiveDocument , ' activate ' )
def repaint ( self , view ) :
self . views_to_repaint [ view ] = True
def repaint ( self , view , fast_render = True ) :
self . views_to_repaint [ view ] = fast_render
QTimer . singleShot ( 10 , self . _do_repaint )
def _do_repaint ( self ) :
from ahb_raster_view import RasterView
import Draft
workbench = Gui . getWorkbench ( " AssemblyHandbookWorkbench " ) #: :type workbench: AssemblyHandbookWorkbench
selection = Gui . Selection . getSelection ( )
to_repaint = self . views_to_repaint . keys ( )
to_repaint = self . views_to_repaint . copy ( )
self . views_to_repaint = { }
for view in to_repaint :
for view , fast_render in to_repaint . items ( ) :
if ' _overlay ' in view . Label :
continue
#print("Repainting " + view.Name)
page = self . getViewPage ( view )
view_cache = self . getViewCache ( view )
view_cache . reset ( )
doc = view . Document
fast_rendering = False
#try:
# fast_rendering = view.Assembly_handbook_FastRendering
#except:
# pass
if view . CoarseView :
fast_rendering = True
selected_balloons = [ ]
for obj in Gui . Selection . getSelection ( ) :
if obj . TypeId == ' TechDraw::DrawViewBalloon ' and obj . SourceView == view and ' Assembly_handbook_Source ' in obj . PropertiesList :
selected_balloons . append ( obj )
#view.clearGeomFormats() # for an unknown reason, this will crash freecad
if not fast_rendering :
is_first_part = True
parts_to_paint = [ ]
# repaint parts that are highlighted by selection
if self . enable_selected_part_highlight :
for balloon in selected_balloons :
part = self . getBalloonSourcePart ( balloon )
if part in view . XSource :
parts_to_paint . append ( part )
# repaint parts that are new in this step (thick line)
prev_view = None
if ' Assembly_handbook_PreviousStepView ' in view . PropertiesList :
prev_view = doc . getObject ( view . Assembly_handbook_PreviousStepView )
for part in view . XSource :
if ( prev_view is None or part not in prev_view . XSource ) and part not in parts_to_paint :
parts_to_paint . append ( part )
if not ' Assembly_handbook_RasterView ' in view . PropertiesList :
view . addProperty ( " App::PropertyBool " , " Assembly_handbook_RasterView " , " Assembly_handbook " )
view . Assembly_handbook_RasterView = True
# make sure the list is not empty, so that we reset all lines
if len ( parts_to_paint ) == 0 :
parts_to_paint . append ( None )
if view . Assembly_handbook_RasterView :
print ( " Rasterizing view " + view . Label + " ... " )
for part in parts_to_paint :
default_line_thickness = 0.05
line_thickness = default_line_thickness
raster_view = RasterView ( view )
raster_view . render ( fast_render )
view . Visibility = False
overlayName = view . Label + " _overlay "
overlay = doc . getObject ( overlayName )
if overlay is None :
overlay = doc . addObject ( ' TechDraw::DrawViewPart ' , overlayName )
page . addView ( overlay )
overlay_frame_name = view . Label + " _frame "
overlay_frame = doc . getObject ( overlay_frame_name )
if overlay_frame is not None :
doc . removeObject ( overlay_frame . Name )
#overlay_frame = Draft.makeWire(points, closed=False, face=False, support=None)
overlay_frame = doc . addObject ( " Part::Part2DObjectPython " , overlay_frame_name )
Draft . Wire ( overlay_frame )
pos = raster_view . projectImageViewPointTo3D ( App . Vector ( 0 , 0 , 0 ) )
pos2 = raster_view . projectImageViewPointTo3D ( App . Vector ( 0.001 , 0.001 , 1 ) )
overlay_frame . Points = [ pos , pos2 ]
Draft . ViewProviderWire ( overlay_frame . ViewObject )
overlay_frame . recompute ( )
default_color = ( 0.0 , 0.0 , 0.0 ) if fast_rendering else ( 0.5 , 0.5 , 0.5 )
color = default_color
overlay_frame2_name = view . Label + " _frame2 "
overlay_frame2 = doc . getObject ( overlay_frame2_name )
if overlay_frame2 is not None :
doc . removeObject ( overlay_frame2 . Name )
overlay_frame2 = doc . addObject ( " Part::Part2DObjectPython " , overlay_frame2_name )
Draft . Wire ( overlay_frame2 )
pos = raster_view . projectImageViewPointTo3D ( App . Vector ( 1 , 1 , 0 ) )
pos2 = raster_view . projectImageViewPointTo3D ( App . Vector ( 1.001 , 1.001 , 1 ) )
overlay_frame2 . Points = [ pos , pos2 ]
Draft . ViewProviderWire ( overlay_frame2 . ViewObject )
overlay_frame2 . recompute ( )
overlay . Source = [ overlay_frame , overlay_frame2 ]
overlay . X = view . X
overlay . Y = view . Y
overlay . Direction = view . Direction
overlay . XDirection = view . XDirection
overlay . ScaleType = view . ScaleType
overlay . Scale = view . Scale
overlay . ViewObject . LineWidth = 0.01
# migrate balloons from source view to overlay
for balloon in page . Views :
if balloon . TypeId == ' TechDraw::DrawViewBalloon ' and " Assembly_handbook_Source " in balloon . PropertiesList and balloon . SourceView == view :
if balloon . SourceView == view :
old_source = balloon . Assembly_handbook_Source
old_OriginOffsetX = balloon . Assembly_handbook_OriginOffsetX
old_OriginOffsetY = balloon . Assembly_handbook_OriginOffsetY
old_X = balloon . X
old_Y = balloon . Y
old_Visibility = balloon . ViewObject . Visibility
balloonName = balloon . Name
doc . removeObject ( balloon . Name )
balloon = doc . addObject ( " TechDraw::DrawViewBalloon " , balloonName )
balloon . SourceView = overlay
balloon . addProperty ( " App::PropertyXLink " , " Assembly_handbook_Source " , " Assembly_handbook " )
balloon . Assembly_handbook_Source = old_source
balloon . addProperty ( " App::PropertyFloat " , " Assembly_handbook_OriginOffsetX " , " Assembly_handbook " )
balloon . addProperty ( " App::PropertyFloat " , " Assembly_handbook_OriginOffsetY " , " Assembly_handbook " )
balloon . Assembly_handbook_OriginOffsetX = old_OriginOffsetX
balloon . Assembly_handbook_OriginOffsetY = old_OriginOffsetY
page . addView ( balloon )
self . updateBalloon ( balloon )
balloon . X = old_X
balloon . Y = old_Y
balloon . ViewObject . Visibility = old_Visibility
balloon . recompute ( )
overlay . recompute ( )
page . recompute ( )
else :
fast_rendering = False
#try:
# fast_rendering = view.Assembly_handbook_FastRendering
#except:
# pass
if view . CoarseView :
fast_rendering = True
selected_balloons = [ ]
for obj in Gui . Selection . getSelection ( ) :
if obj . TypeId == ' TechDraw::DrawViewBalloon ' and obj . SourceView == view and ' Assembly_handbook_Source ' in obj . PropertiesList :
selected_balloons . append ( obj )
#view.clearGeomFormats() # for an unknown reason, this will crash freecad
if not fast_rendering :
is_first_part = True
parts_to_paint = [ ]
# repaint parts that are highlighted by selection
if self . enable_selected_part_highlight :
for balloon in selected_balloons :
part = self . getBalloonSourcePart ( balloon )
if part in view . XSource :
parts_to_paint . append ( part )
# repaint parts that are new in this step (thick line)
prev_view = None
if ' Assembly_handbook_PreviousStepView ' in view . PropertiesList :
prev_view = doc . getObject ( view . Assembly_handbook_PreviousStepView )
for part in view . XSource :
if ( prev_view is None or part not in prev_view . XSource ) and part not in parts_to_paint :
parts_to_paint . append ( part )
# make sure the list is not empty, so that we reset all lines
if len ( parts_to_paint ) == 0 :
parts_to_paint . append ( None )
if part is not None :
part_view = workbench . partsCache . getPart2DView ( view , part )
for part in parts_to_paint :
default_line_thickness = 0.05
line_thickness = default_line_thickness
center = self . computePartCenter ( view , part )
if self . isNewPartInView ( view , part ) :
line_thickness = 0.2
color = ( 0 , 0 , 0 )
default_color = ( 0.0 , 0.0 , 0.0 ) if fast_rendering else ( 0.5 , 0.5 , 0.5 )
color = default_color
if self . enable_selected_part_highlight :
for balloon in selected_balloons :
if part == self . getBalloonSourcePart ( balloon ) :
color = ( 0.0 , 0.85 , 0.0 ) # selection highlighting
# iterate edges of actual view and highlight matching edges
for edgeIdx in range ( 10000 ) :
hasEdge = False
try :
edge = view . getEdgeByIndex ( edgeIdx )
hasEdge = True
except :
pass
if not hasEdge :
break
if part is not None :
part_view = workbench . partsCache . getPart2DView ( view , part )
center = self . computePartCenter ( view , part )
if self . isNewPartInView ( view , part ) :
line_thickness = 0.2
color = ( 0 , 0 , 0 )
if self . enable_selected_part_highlight :
for balloon in selected_balloons :
if part == self . getBalloonSourcePart ( balloon ) :
color = ( 0.0 , 0.85 , 0.0 ) # selection highlighting
is_edge_of_part = False
if part is not None and ( not hasattr ( edge . Curve , ' Degree ' ) or edge . Curve . Degree == 1 ) and len ( edge . Vertexes ) == 2 :
edgeData = [
edge . Vertexes [ 0 ] . X - center . x ,
edge . Vertexes [ 0 ] . Y - center . y ,
edge . Vertexes [ 1 ] . X - center . x ,
edge . Vertexes [ 1 ] . Y - center . y
]
v0 = App . Vector ( edgeData [ 0 ] , edgeData [ 1 ] )
v1 = App . Vector ( edgeData [ 2 ] , edgeData [ 3 ] )
# iterate edges of actual view and highlight matching edges
for edgeIdx in range ( 10000 ) :
hasEdge = False
try :
edge = view . getEdgeByIndex ( edgeIdx )
hasEdge = True
except :
pass
if not hasEdge :
break
for line in part_view . cached_lines :
l0 = App . Vector ( line [ 0 ] , line [ 1 ] )
l1 = App . Vector ( line [ 2 ] , line [ 3 ] )
#d = abs(edgeData[0] - line[0]) + abs(edgeData[1] - line[1]) + abs(edgeData[2] - line[2]) + abs(edgeData[3] - line[3])
d = v0 . distanceToLineSegment ( l0 , l1 ) . Length + v1 . distanceToLineSegment ( l0 , l1 ) . Length
if d < 0.01 :
is_edge_of_part = True
break
is_edge_of_part = False
if part is not None and ( not hasattr ( edge . Curve , ' Degree ' ) or edge . Curve . Degree == 1 ) and len ( edge . Vertexes ) == 2 :
edgeData = [
edge . Vertexes [ 0 ] . X - center . x ,
edge . Vertexes [ 0 ] . Y - center . y ,
edge . Vertexes [ 1 ] . X - center . x ,
edge . Vertexes [ 1 ] . Y - center . y
]
v0 = App . Vector ( edgeData [ 0 ] , edgeData [ 1 ] )
v1 = App . Vector ( edgeData [ 2 ] , edgeData [ 3 ] )
if is_edge_of_part :
view . formatGeometricEdge ( edgeIdx , 1 , line_thickness , color , True )
elif is_first_part :
# reset edge format
view . formatGeometricEdge ( edgeIdx , 1 , default_line_thickness , default_color , True )
is_first_part = False
view . requestPaint ( )
for line in part_view . cached_lines :
l0 = App . Vector ( line [ 0 ] , line [ 1 ] )
l1 = App . Vector ( line [ 2 ] , line [ 3 ] )
#d = abs(edgeData[0] - line[0]) + abs(edgeData[1] - line[1]) + abs(edgeData[2] - line[2]) + abs(edgeData[3] - line[3])
d = v0 . distanceToLineSegment ( l0 , l1 ) . Length + v1 . distanceToLineSegment ( l0 , l1 ) . Length
if d < 0.01 :
is_edge_of_part = True
break
if is_edge_of_part :
view . formatGeometricEdge ( edgeIdx , 1 , line_thickness , color , True )
elif is_first_part :
# reset edge format
view . formatGeometricEdge ( edgeIdx , 1 , default_line_thickness , default_color , True )
is_first_part = False
view . requestPaint ( )
def updateBalloonCursor ( self , view ) :
selected_balloons = [ ]
for obj in Gui . Selection . getSelection ( ) :
@ -208,6 +310,13 @@ class TechDrawExtensions:
selected_balloons . append ( obj )
cursor = self . view_cursors . get ( view , None )
if cursor is not None :
try :
cursor . x ( ) # this can throw an exception if the Qt item has been deleted (for example when closing the page)
except Exception as ex :
print ( " Re-generating cursor... " )
cursor = None
if cursor is None :
cursor = CursorItem ( view = view )
TDG . addQGIToView ( view , cursor ) ;
@ -227,7 +336,7 @@ class TechDrawExtensions:
if doc != Gui . ActiveDocument . Document :
raise Exception ( " Current view is not for the same document as TechDraw view " + view . Name )
activeView = Gui . ActiveDocument . ActiveView
if str ( type ( activeView ) ) != " <class ' View3DInventorPy ' > " :
if str ( type ( activeView ) ) not in [ " <class ' View3DInventorPy ' > " , " <class ' Gui.View3DInventor ' > " ] :
raise Exception ( " Current view is not a 3D view " )
cam = activeView . getCameraNode ( )
@ -315,7 +424,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
@ -327,7 +436,7 @@ class TechDrawExtensions:
view = balloon . SourceView
self . updateBalloonCursor ( view )
if self . enable_selected_part_highlight :
self . repaint ( view ) # disabled for now, for performance reasons
self . repaint ( view )
def onBalloonChanged ( self , obj , prop ) :
# Avoid reentry
@ -339,31 +448,94 @@ class TechDrawExtensions:
self . updating_balloon = True
self . updateBalloon ( obj )
self . updating_balloon = False
def add_or_update_balloon ( self , view , part , parent_path ) :
balloonsCreated = [ ]
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 )
if not self . isNewPartInView ( view , part ) :
balloon . ViewObject . Visibility = False
else :
balloonsCreated . append ( balloon )
else :
self . updateBalloon ( balloon )
return balloonsCreated
def updateBalloon ( self , balloon ) :
workbench = Gui . getWorkbench ( " AssemblyHandbookWorkbench " ) #: :type workbench: AssemblyHandbookWorkbench
view = balloon . SourceView
obj = self . getBalloonSourcePart ( balloon )
path = self . getBalloonSourcePartPath ( balloon )
partDisplayName = self . getPartDisplayName ( obj )
objectCenterView = workbench . techDrawExtensions . computePartCenter ( view , obj )
if obj is not None :
objectCenterView = workbench . techDrawExtensions . computePartCenter ( view , obj , path )
balloon . OriginX = objectCenterView . x + balloon . Assembly_handbook_OriginOffsetX
balloon . OriginY = objectCenterView . y + balloon . Assembly_handbook_OriginOffsetY
balloon . OriginX = objectCenterView . x + balloon . Assembly_handbook_OriginOffsetX
balloon . OriginY = objectCenterView . y + balloon . Assembly_handbook_OriginOffsetY
partDisplayName = ' Inconnu ' if obj is None else self . getPartDisplayName ( obj )
balloon . Text = partDisplayName
balloon . Text = partDisplayName
balloon . ViewObject . Font = ' DejaVu Sans '
balloon . ViewObject . Fontsize = 4
balloon . BubbleShape = ' Inspection '
balloon . EndTypeScale = 1
balloon . EndTypeScale = 0.5
def getBalloonSourcePart ( self , balloon ) :
try :
return balloon . Assembly_handbook_Source [ 0 ]
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 is None :
@ -409,9 +581,17 @@ class TechDrawExtensions:
return obj
return None
def forceRedrawPage ( self , page , callback = None ) :
def forceRedrawPage ( self , page , callback = None , fast_render = True ) :
for view in page . Views :
if view . TypeId == ' TechDraw::DrawViewPart ' and ' Assembly_handbook_PreviousStepView ' in view . PropertiesList :
if not ' Assembly_handbook_RasterView ' in view . PropertiesList :
view . addProperty ( " App::PropertyBool " , " Assembly_handbook_RasterView " , " Assembly_handbook " )
view . Assembly_handbook_RasterView = True
if ' Assembly_handbook_RasterView ' in view . PropertiesList and view . Assembly_handbook_RasterView :
view . purgeTouched ( ) # make sure we don't trigger rendering of source views (this is awfully slow and doesn't even work for a lot of models)
else :
view . touch ( )
self . refreshView ( view )
elif view . TypeId == ' TechDraw::DrawViewBalloon ' :
if view . ViewObject . Visibility :
@ -434,29 +614,133 @@ class TechDrawExtensions:
for view in page . Views :
if view . TypeId == ' TechDraw::DrawViewPart ' :
view . recompute ( )
self . repaint ( view )
self . repaint ( view , fast_render )
if callback is not None :
callback ( )
else :
page . KeepUpdated = True
def restoreKeepUpdated ( ) :
for view in page . Views :
if view . TypeId == ' TechDraw::DrawViewPart ' :
if view . Name . endswith ( ' _overlay ' ) :
view . touch ( )
view . recompute ( )
for sub_view in page . Views :
try :
if sub_view . SourceView == view :
sub_view . recompute ( )
except :
pass
else :
view . recompute ( )
self . repaint ( view , fast_render )
page . KeepUpdated = False
if callback is not None :
callback ( )
QTimer . singleShot ( 10 , restoreKeepUpdated )
def refreshOverlays ( self , page , callback = None ) :
import os
for view in page . Views :
if view . TypeId == ' TechDraw::DrawViewPart ' and ' Assembly_handbook_RasterView ' in view . PropertiesList and view . Assembly_handbook_RasterView :
view . purgeTouched ( ) # make sure we don't trigger rendering of source views (this is awfully slow and doesn't even work for a lot of models)
doc = page . Document
for image in page . Views :
if image . TypeId == ' TechDraw::DrawViewImage ' :
folder_name = ' / ' + os . path . basename ( doc . FileName ) . replace ( ' .FCStd ' , ' ' ) + ' _raster/ '
if folder_name in image . ImageFile :
full_path = doc . FileName . replace ( ' .FCStd ' , ' ' ) + ' _raster/ ' + image . ImageFile . split ( folder_name ) [ 1 ]
if image . ImageFile != full_path :
image . ImageFile = full_path
if page . KeepUpdated :
if callback :
callback ( )
else :
page . KeepUpdated = True
def restoreKeepUpdated ( ) :
for view in page . Views :
if view . TypeId == ' TechDraw::DrawViewPart ' :
self . repaint ( view )
if view . Name . endswith ( ' _overlay ' ) :
view . touch ( )
view . recompute ( )
for sub_view in page . Views :
try :
if sub_view . SourceView == view :
sub_view . recompute ( )
except :
pass
page . KeepUpdated = False
for view in page . Views :
if view . TypeId == ' TechDraw::DrawViewBalloon ' :
if view . ViewObject . Visibility :
# workaround for a TechDraw bug: sometimes the balloon should be visible but doesn't appear, showing it again fixes the issue
view . ViewObject . Visibility = False
def makeRedrawCallback ( view ) :
def redrawBalloon ( ) :
view . ViewObject . Visibility = True
return redrawBalloon
QTimer . singleShot ( 0 , makeRedrawCallback ( view ) )
else :
# workaround for a TechDraw bug: sometimes the balloon text is visible even if the balloon is hidden, hiding it again fixes the issue
view . ViewObject . Visibility = True
view . ViewObject . Visibility = False
if callback is not None :
callback ( )
QTimer . singleShot ( 10 , restoreKeepUpdated )
def computePartCenter ( self , view , obj ) :
def getSourceView ( self , view ) :
if view . Name . endswith ( ' _overlay ' ) :
view = view . Document . getObject ( view . Name [ 0 : - 8 ] )
if view is None :
raise Exception ( " Can ' t find source view of " + view . Name )
return view
def getOverlayView ( self , view ) :
if view . Name . endswith ( ' _overlay ' ) :
return view
overlay = view . Document . getObject ( view . Name + ' _overlay ' )
return overlay if overlay is not None else view
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)
@ -475,6 +759,12 @@ class TechDrawExtensions:
return self . projectPoint ( view , objectCenterWorld )
def projectPoint ( self , view , point3d ) :
if ' Assembly_handbook_RasterView ' in view . PropertiesList and view . Assembly_handbook_RasterView :
from ahb_raster_view import RasterView
raster_view = RasterView ( view )
if raster_view . init_image_projection ( ) :
return raster_view . project3DPointToSourceView ( point3d )
# DrawViewPart::projectPoint should be exposed to python in freecad 0.21, but for 0.20 we have to use a workaround
view_cache = self . getViewCache ( view )
if view_cache . projected_origin is None :
@ -492,3 +782,48 @@ class TechDrawExtensions:
cache = ViewCache ( )
self . view_cache [ view ] = cache
return cache
def onDocumentEvent ( self , doc , event ) :
if event == ' activate ' :
if doc not in self . initialized_documents :
self . initialized_documents . append ( doc )
self . initializeDocument ( doc )
elif event == ' deleted ' :
if doc in self . initialized_documents :
self . initialized_documents . remove ( doc )
def initializeDocument ( self , doc ) :
def doInit ( ) :
main_part = None
try :
for obj in doc . Objects :
if obj . TypeId == ' TechDraw::DrawPage ' :
self . onPageLoaded ( obj )
main_parts = doc . getObjectsByLabel ( doc . Name )
if len ( main_parts ) == 1 :
main_part = main_parts [ 0 ]
except :
pass
if main_part is not None :
self . initPartMetadata ( main_part )
QTimer . singleShot ( 0 , doInit )
def initPartMetadata ( self , part ) :
current_material = ' Unknown '
if ' Assembly_handbook_Material ' in part . PropertiesList :
current_material = part . Assembly_handbook_Material
else :
part . addProperty ( " App::PropertyEnumeration " , " Assembly_handbook_Material " , " Assembly_handbook " )
material_list = [ ' Unknown ' ] + Material . GetMaterialIDs ( )
part . Assembly_handbook_Material = material_list
part . Assembly_handbook_Material = material_list . index ( current_material ) if current_material in material_list else 0
if ' Assembly_handbook_Weight ' not in part . PropertiesList :
part . addProperty ( " App::PropertyFloat " , " Assembly_handbook_Weight " , " Assembly_handbook " , ' Part weight in grams. Set a negative number if weight is unknown. ' )
part . Assembly_handbook_Weight = - 1
def onPageLoaded ( self , page ) :
self . refreshOverlays ( page )