|
|
|
@ -94,113 +94,173 @@ class TechDrawExtensions:
|
|
|
|
|
for view in to_repaint: |
|
|
|
|
#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 = [] |
|
|
|
|
if not 'Assembly_handbook_RasterView' in view.PropertiesList: |
|
|
|
|
view.addProperty("App::PropertyBool", "Assembly_handbook_RasterView", "Assembly_handbook") |
|
|
|
|
|
|
|
|
|
# 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: |
|
|
|
|
if view.Assembly_handbook_RasterView: |
|
|
|
|
print("Rasterizing view " + view.Label + "...") |
|
|
|
|
imageName = view.Label + "_raster" |
|
|
|
|
image = doc.getObject(imageName) |
|
|
|
|
if image is None: |
|
|
|
|
image = doc.addObject('TechDraw::DrawViewImage', view.Label + "_raster") |
|
|
|
|
|
|
|
|
|
if not image in page.Views: |
|
|
|
|
page.addView(image) |
|
|
|
|
|
|
|
|
|
new_views_list = page.Views |
|
|
|
|
new_views_list.remove(image) |
|
|
|
|
view_idx = new_views_list.index(view) |
|
|
|
|
new_views_list.insert(view_idx, image) |
|
|
|
|
page.Views = new_views_list |
|
|
|
|
|
|
|
|
|
image_file_name = doc.FileName.replace('.FCStd', '') + '_raster/' + view.Name + '.png' |
|
|
|
|
self.rasterizeView(view, image_file_name) |
|
|
|
|
image.ImageFile = image_file_name # TODO: see if it's possible to set a relative path |
|
|
|
|
image.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) |
|
|
|
|
|
|
|
|
|
# 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) |
|
|
|
|
|
|
|
|
|
for part in parts_to_paint: |
|
|
|
|
default_line_thickness = 0.05 |
|
|
|
|
line_thickness = default_line_thickness |
|
|
|
|
|
|
|
|
|
default_color = (0.0, 0.0, 0.0) if fast_rendering else (0.5, 0.5, 0.5) |
|
|
|
|
color = default_color |
|
|
|
|
# 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 rasterizeView(self, view, image_file_name): |
|
|
|
|
from pivy import coin |
|
|
|
|
import os |
|
|
|
|
|
|
|
|
|
print('Rasterizing ' + view.Label + " to " + image_file_name + "...") |
|
|
|
|
|
|
|
|
|
dir = os.path.dirname(image_file_name) |
|
|
|
|
if not os.path.exists(dir): |
|
|
|
|
os.makedirs(dir) |
|
|
|
|
|
|
|
|
|
doc = App.newDocument('tmp_raster', hidden=False, temp=False) |
|
|
|
|
for part in view.XSource: |
|
|
|
|
link = doc.addObject('App::Link', part.Name) |
|
|
|
|
link.Label = part.Label |
|
|
|
|
if part.TypeId == 'App::Link': |
|
|
|
|
link.LinkedObject = part.LinkedObject |
|
|
|
|
link.Placement = part.Placement |
|
|
|
|
else: |
|
|
|
|
link.LinkedObject = part |
|
|
|
|
|
|
|
|
|
docView = Gui.getDocument(doc.Name).mdiViewsOfType('Gui::View3DInventor')[0] |
|
|
|
|
|
|
|
|
|
cam = docView.getCameraNode() |
|
|
|
|
|
|
|
|
|
rot = coin.SbRotation(coin.SbVec3f(1,0,0), coin.SbVec3f(view.XDirection.x,view.XDirection.y,view.XDirection.z)) |
|
|
|
|
rot *= coin.SbRotation(coin.SbVec3f(0,0,1), coin.SbVec3f(view.Direction.x,view.Direction.y,view.Direction.z)) |
|
|
|
|
cam.orientation.setValue(rot) |
|
|
|
|
|
|
|
|
|
docView.fitAll() |
|
|
|
|
|
|
|
|
|
docView.saveImage(image_file_name, 4096, 4096, "#ffffff") |
|
|
|
|
|
|
|
|
|
App.closeDocument(doc.Name) |
|
|
|
|
|
|
|
|
|
def updateBalloonCursor(self, view): |
|
|
|
|
selected_balloons = [] |
|
|
|
|
for obj in Gui.Selection.getSelection(): |
|
|
|
@ -227,7 +287,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() |
|
|
|
@ -408,8 +468,11 @@ class TechDrawExtensions:
|
|
|
|
|
return None |
|
|
|
|
|
|
|
|
|
def forceRedrawPage(self, page, callback = None): |
|
|
|
|
needPageUpdate = False |
|
|
|
|
for view in page.Views: |
|
|
|
|
if view.TypeId == 'TechDraw::DrawViewPart' and 'Assembly_handbook_PreviousStepView' in view.PropertiesList: |
|
|
|
|
if 'Assembly_handbook_RasterView' not in view.PropertiesList or not view.Assembly_handbook_RasterView: |
|
|
|
|
needPageUpdate = True |
|
|
|
|
self.refreshView(view) |
|
|
|
|
elif view.TypeId == 'TechDraw::DrawViewBalloon': |
|
|
|
|
if view.ViewObject.Visibility: |
|
|
|
@ -425,7 +488,7 @@ class TechDrawExtensions:
|
|
|
|
|
view.ViewObject.Visibility = True |
|
|
|
|
view.ViewObject.Visibility = False |
|
|
|
|
|
|
|
|
|
if page.KeepUpdated: |
|
|
|
|
if page.KeepUpdated or not needPageUpdate: |
|
|
|
|
for view in page.Views: |
|
|
|
|
if view.TypeId != 'TechDraw::DrawViewPart': |
|
|
|
|
view.recompute() |
|
|
|
|