Browse Source

fixed bugs

dev/better-annotations
Youen 2 years ago
parent
commit
f9d58c66fc
  1. 10
      ahb_cmd_view_annotate.py
  2. 51
      ahb_raster_view.py
  3. 61
      ahb_techdraw_extensions.py

10
ahb_cmd_view_annotate.py

@ -21,6 +21,8 @@ class AHB_View_Annotate:
if view.TypeId != 'TechDraw::DrawViewPart': if view.TypeId != 'TechDraw::DrawViewPart':
raise Exception("Selected object is not a TechDraw view") raise Exception("Selected object is not a TechDraw view")
overlay_view = workbench.techDrawExtensions.getOverlayView(view)
doc = view.Document doc = view.Document
page = workbench.techDrawExtensions.getViewPage(view) page = workbench.techDrawExtensions.getViewPage(view)
@ -30,7 +32,7 @@ class AHB_View_Annotate:
# 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: 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 view.XSource:
ref_name = "<no ref>" ref_name = "<no ref>"
@ -47,13 +49,9 @@ class AHB_View_Annotate:
# Search an existing balloon to update # Search an existing balloon to update
for obj in page.Views: for obj in page.Views:
if obj.TypeId == 'TechDraw::DrawViewBalloon' and workbench.techDrawExtensions.getBalloonSourcePart(obj) == partLink: if obj.TypeId == 'TechDraw::DrawViewBalloon' and workbench.techDrawExtensions.getBalloonSourcePart(obj) == partLink:
if obj.SourceView != view: continue if obj.SourceView != overlay_view: continue
balloon = obj balloon = obj
overlay_view = doc.getObject(view.Name + '_overlay')
if overlay_view is None:
overlay_view = view
# Create a new balloon if needed # Create a new balloon if needed
if balloon is None: if balloon is None:
partName = partLink.Name partName = partLink.Name

51
ahb_raster_view.py

@ -7,6 +7,21 @@ class RasterView:
doc = view.Document doc = view.Document
self.image_file_name = doc.FileName.replace('.FCStd', '') + '_raster/' + view.Name + '.png' self.image_file_name = doc.FileName.replace('.FCStd', '') + '_raster/' + view.Name + '.png'
def init_image_projection(self):
doc = self.source_view.Document
image_name = self.source_view.Label + "_raster"
image = doc.getObject(image_name)
if image is None:
return False
self.image_view = image
if image.Assembly_handbook_ViewVolumeWidth > 0:
self._precompute_image_projection()
return True
return False
def init_image(self): def init_image(self):
workbench = Gui.getWorkbench("AssemblyHandbookWorkbench") #: :type workbench: AssemblyHandbookWorkbench workbench = Gui.getWorkbench("AssemblyHandbookWorkbench") #: :type workbench: AssemblyHandbookWorkbench
@ -34,9 +49,9 @@ class RasterView:
self.image_view = image self.image_view = image
if image.Assembly_handbook_ViewVolumeWidth > 0: if image.Assembly_handbook_ViewVolumeWidth > 0:
self.init_image_projection() self._precompute_image_projection()
def init_image_projection(self): def _precompute_image_projection(self):
YDirection = self.source_view.Direction.cross(self.source_view.XDirection) YDirection = self.source_view.Direction.cross(self.source_view.XDirection)
self.image_x_dir = self.source_view.XDirection / self.image_view.Assembly_handbook_ViewVolumeWidth self.image_x_dir = self.source_view.XDirection / self.image_view.Assembly_handbook_ViewVolumeWidth
@ -51,6 +66,15 @@ class RasterView:
offset = self.image_view.Assembly_handbook_ViewVolumeOffset offset = self.image_view.Assembly_handbook_ViewVolumeOffset
return App.Vector(self.image_x_dir.dot(point3d) + offset.x, self.image_y_dir.dot(point3d) + offset.y, self.image_z_dir.dot(point3d) + offset.z) return App.Vector(self.image_x_dir.dot(point3d) + offset.x, self.image_y_dir.dot(point3d) + offset.y, self.image_z_dir.dot(point3d) + offset.z)
def project3DPointToSourceView(self, point3d):
offset = self.image_view.Assembly_handbook_ViewVolumeOffset
offset = App.Vector((offset.x-0.5) * self.image_view.Assembly_handbook_ViewVolumeWidth, (offset.y-0.5) * self.image_view.Assembly_handbook_ViewVolumeHeight, (offset.z-0.5) * self.image_view.Assembly_handbook_ViewVolumeDepth)
#image_view_point = App.Vector(self.image_x_dir.dot(point3d), self.image_y_dir.dot(point3d), self.image_z_dir.dot(point3d))
#return App.Vector(image_view_point.x * self.image_view.Assembly_handbook_ViewVolumeWidth, image_view_point.y * self.image_view.Assembly_handbook_ViewVolumeHeight, 0)
YDirection = self.source_view.Direction.cross(self.source_view.XDirection)
return App.Vector(self.source_view.XDirection.dot(point3d) + offset.x, YDirection.dot(point3d) + offset.y, self.image_z_dir.dot(point3d) + offset.z)
def projectImageViewPointTo3D(self, point2d): def projectImageViewPointTo3D(self, point2d):
offset = self.image_view.Assembly_handbook_ViewVolumeOffset offset = self.image_view.Assembly_handbook_ViewVolumeOffset
p = point2d - offset p = point2d - offset
@ -96,25 +120,15 @@ class RasterView:
self.image_view.Assembly_handbook_ViewVolumeHeight = viewVolume.getHeight() self.image_view.Assembly_handbook_ViewVolumeHeight = viewVolume.getHeight()
self.image_view.Assembly_handbook_ViewVolumeDepth = viewVolume.getDepth() self.image_view.Assembly_handbook_ViewVolumeDepth = viewVolume.getDepth()
sb_offset = viewVolume.projectToScreen(coin.SbVec3f(0,0,0))
self.image_view.Assembly_handbook_ViewVolumeOffset = App.Vector(sb_offset[0], sb_offset[1], sb_offset[2])
self.init_image_projection()
docView.saveImage(self.image_file_name, 4096, 4096, "#ffffff") docView.saveImage(self.image_file_name, 4096, 4096, "#ffffff")
with Image.open(self.image_file_name) as img: with Image.open(self.image_file_name) as img:
original_size = img.size original_size = img.size
p2dA = self.project3DPointToImageView(App.Vector(0,0,0))
p2dB = self.project3DPointToImageView(view.XDirection)
imageScale = view.Scale / (p2dB.x - p2dA.x) / original_size[0] * 10
#print('imageScale', imageScale)
bg = Image.new(img.mode, img.size, '#ffffff') # fills an image with the background color bg = Image.new(img.mode, img.size, '#ffffff') # fills an image with the background color
diff = ImageChops.difference(img, bg) # diff between the actual image and the background color diff = ImageChops.difference(img, bg) # diff between the actual image and the background color
bbox = diff.getbbox() # finds border size (non-black portion of the image) bbox = diff.getbbox() # finds border size (non-black portion of the image)
print(bbox) #print(bbox)
#image_center = (bbox[0] + (bbox[2] - bbox[0])/2 - img.size[0]/2, bbox[1] + (bbox[3] - bbox[1])/2 - img.size[1]/2) #image_center = (bbox[0] + (bbox[2] - bbox[0])/2 - img.size[0]/2, bbox[1] + (bbox[3] - bbox[1])/2 - img.size[1]/2)
#print(image_center) #print(image_center)
img = img.crop(bbox) img = img.crop(bbox)
@ -135,6 +149,17 @@ class RasterView:
#debugPoint(App.Vector(131.23702882966705, -655.0000021095163, 145.21130178331268)) #debugPoint(App.Vector(131.23702882966705, -655.0000021095163, 145.21130178331268))
img.save(self.image_file_name) img.save(self.image_file_name)
sb_offset = viewVolume.projectToScreen(coin.SbVec3f(0,0,0))
crop_offset = App.Vector(((bbox[0] + bbox[2])/2 - original_size[0]/2)/original_size[0], ((bbox[1] + bbox[3])/2 - original_size[1]/2)/original_size[1], 0)
self.image_view.Assembly_handbook_ViewVolumeOffset = App.Vector(sb_offset[0] - crop_offset.x, sb_offset[1] + crop_offset.y, sb_offset[2])
self._precompute_image_projection()
p2dA = self.project3DPointToImageView(App.Vector(0,0,0))
p2dB = self.project3DPointToImageView(view.XDirection)
imageScale = view.Scale / (p2dB.x - p2dA.x) / original_size[0] * 10
#print('imageScale', imageScale)
App.closeDocument(doc.Name) App.closeDocument(doc.Name)

61
ahb_techdraw_extensions.py

@ -16,6 +16,9 @@ class CursorItem(QtGui.QGraphicsItem):
self.size = 100.0 self.size = 100.0
self.view = view self.view = view
def removeSceneEventFilter(self, a, b):
print('removeSceneEventFilter', a, b)
def onViewPosChange(self, callback): def onViewPosChange(self, callback):
self.viewPosChangeCallback = callback self.viewPosChangeCallback = callback
@ -173,11 +176,33 @@ class TechDrawExtensions:
overlay.Scale = view.Scale overlay.Scale = view.Scale
overlay.ViewObject.LineWidth = 0.01 overlay.ViewObject.LineWidth = 0.01
# migrate balloons from source view to overlay
for balloon in page.Views: for balloon in page.Views:
if balloon.TypeId == 'TechDraw::DrawViewBalloon' and "Assembly_handbook_Source" in balloon.PropertiesList and balloon.SourceView == view: if balloon.TypeId == 'TechDraw::DrawViewBalloon' and "Assembly_handbook_Source" in balloon.PropertiesList and balloon.SourceView == view:
if 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.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) page.addView(balloon)
self.updateBalloon(balloon)
balloon.X = old_X
balloon.Y = old_Y
balloon.ViewObject.Visibility = old_Visibility
balloon.recompute() balloon.recompute()
page.KeepUpdated = True # once we have hidden the source view, there should be no performance issue page.KeepUpdated = True # once we have hidden the source view, there should be no performance issue
@ -293,6 +318,13 @@ class TechDrawExtensions:
selected_balloons.append(obj) selected_balloons.append(obj)
cursor = self.view_cursors.get(view, None) 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: if cursor is None:
cursor = CursorItem(view = view) cursor = CursorItem(view = view)
TDG.addQGIToView(view, cursor); TDG.addQGIToView(view, cursor);
@ -412,7 +444,7 @@ class TechDrawExtensions:
view = balloon.SourceView view = balloon.SourceView
self.updateBalloonCursor(view) self.updateBalloonCursor(view)
if self.enable_selected_part_highlight: if self.enable_selected_part_highlight:
self.repaint(view) # disabled for now, for performance reasons self.repaint(view)
def onBalloonChanged(self, obj, prop): def onBalloonChanged(self, obj, prop):
# Avoid reentry # Avoid reentry
@ -496,6 +528,10 @@ class TechDrawExtensions:
needPageUpdate = False needPageUpdate = False
for view in page.Views: for view in page.Views:
if view.TypeId == 'TechDraw::DrawViewPart' and 'Assembly_handbook_PreviousStepView' in view.PropertiesList: 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' not in view.PropertiesList or not view.Assembly_handbook_RasterView: if 'Assembly_handbook_RasterView' not in view.PropertiesList or not view.Assembly_handbook_RasterView:
needPageUpdate = True needPageUpdate = True
self.refreshView(view) self.refreshView(view)
@ -534,7 +570,24 @@ class TechDrawExtensions:
callback() callback()
QTimer.singleShot(10, restoreKeepUpdated) QTimer.singleShot(10, restoreKeepUpdated)
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): def computePartCenter(self, view, obj):
view = self.getSourceView(view)
if obj.TypeId == 'App::Link': if obj.TypeId == 'App::Link':
partLink = obj partLink = obj
objectCenterWorld = partLink.LinkPlacement.Matrix.multiply(partLink.LinkedObject.Shape.CenterOfGravity) objectCenterWorld = partLink.LinkPlacement.Matrix.multiply(partLink.LinkedObject.Shape.CenterOfGravity)
@ -561,6 +614,12 @@ class TechDrawExtensions:
return self.projectPoint(view, objectCenterWorld) return self.projectPoint(view, objectCenterWorld)
def projectPoint(self, view, point3d): def projectPoint(self, view, point3d):
if 'Assembly_handbook_RasterView' in view.PropertiesList or 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 # 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) view_cache = self.getViewCache(view)
if view_cache.projected_origin is None: if view_cache.projected_origin is None:

Loading…
Cancel
Save