Draft: fix handling of Links in TD DraftViews

Forum topic:
https://forum.freecad.org/viewtopic.php?t=92476

For LinkGroups and Links to Std_Groups that do not have a default placement, a temporary hidden document is used to handle the placement of their children. This is a bit of a hack of course.
This commit is contained in:
Roy-043
2024-11-28 22:38:07 +01:00
committed by Yorik van Havre
parent 1819b79376
commit 8d54fdc0bc

View File

@@ -103,8 +103,9 @@ def get_arrow(obj,
arrowtype, point, arrowsize, color, linewidth, angle=0):
"""Get the SVG representation from an arrow."""
svg = ""
vobj = _get_view_object(obj)
if not App.GuiUp or not obj.ViewObject:
if not App.GuiUp or vobj is None:
return svg
_cx_cy_r = 'cx="{}" cy="{}" r="{}"'.format(point.x, point.y, arrowsize)
@@ -114,7 +115,7 @@ def get_arrow(obj,
_scale = 'scale({size},{size})'.format(size=arrowsize)
_style = 'style="stroke-miterlimit:4;stroke-dasharray:none;stroke-linecap:square"'
if obj.ViewObject.ArrowType == "Circle":
if vobj.ArrowType == "Circle":
svg += '<circle '
svg += _cx_cy_r + ' '
svg += 'fill="{}" stroke="{}" '.format("none", color)
@@ -122,14 +123,14 @@ def get_arrow(obj,
svg += 'stroke-miterlimit:4;stroke-dasharray:none;stroke-linecap:square" '
svg += 'freecad:skip="1"'
svg += '/>\n'
elif obj.ViewObject.ArrowType == "Dot":
elif vobj.ArrowType == "Dot":
svg += '<circle '
svg += _cx_cy_r + ' '
svg += 'fill="{}" stroke="{}" '.format(color, "none")
svg += _style + ' '
svg += 'freecad:skip="1"'
svg += '/>\n'
elif obj.ViewObject.ArrowType == "Arrow":
elif vobj.ArrowType == "Arrow":
svg += '<path '
svg += 'transform="'
svg += _rotate + ' '
@@ -140,7 +141,7 @@ def get_arrow(obj,
svg += _style + ' '
svg += 'd="M 0 0 L 4 1 L 4 -1 Z"'
svg += '/>\n'
elif obj.ViewObject.ArrowType == "Tick":
elif vobj.ArrowType == "Tick":
svg += '<path '
svg += 'transform="'
svg += _rotate + ' '
@@ -151,7 +152,7 @@ def get_arrow(obj,
svg += _style + ' '
svg += 'd="M -1 -2 L 0 2 L 1 2 L 0 -2 Z"'
svg += '/>\n'
elif obj.ViewObject.ArrowType == "Tick-2":
elif vobj.ArrowType == "Tick-2":
svg += '<line '
svg += 'transform="'
svg += 'rotate({},{},{}) '.format(math.degrees(angle) + 45,
@@ -233,12 +234,13 @@ def _svg_dimension(obj, plane, scale, linewidth, fontsize,
"in GUI mode".format(obj.Label))
return ""
if not hasattr(obj.ViewObject, "Proxy") or not obj.ViewObject.Proxy:
vobj = _get_view_object(obj)
if not hasattr(vobj, "Proxy") or not vobj.Proxy:
_err("'{}': doesn't have Proxy, "
"SVG cannot be generated".format(obj.Label))
return ""
vobj = obj.ViewObject
prx = vobj.Proxy
if not hasattr(prx, "p1"):
@@ -425,25 +427,63 @@ def get_svg(obj,
# all the SVG strings from the contents of the group
if hasattr(obj, "isDerivedFrom"):
if (obj.isDerivedFrom("App::DocumentObjectGroup")
or utils.get_type(obj) in ["Layer","BuildingPart"]):
or utils.get_type(obj) in ["Layer", "BuildingPart"]
or obj.isDerivedFrom("App::LinkGroup")
or (obj.isDerivedFrom("App::Link")
and obj.LinkedObject.isDerivedFrom("App::DocumentObjectGroup"))):
hidden_doc = None
if (obj.isDerivedFrom("App::LinkGroup")
or (obj.isDerivedFrom("App::Link")
and obj.LinkedObject.isDerivedFrom("App::DocumentObjectGroup"))):
if obj.Placement.isIdentity():
if obj.isDerivedFrom("App::LinkGroup"):
group = obj.ElementList
else:
group = obj.Group
else:
# Using a hidden doc hack to handle placements.
hidden_doc = App.newDocument(name="hidden", hidden=True, temp=True)
new = hidden_doc.copyObject(obj, True)
pla = new.Placement
new.Placement = App.Placement()
if new.isDerivedFrom("App::LinkGroup"):
group = new.ElementList
else:
group = new.Group
for child in group:
child.Placement = pla * child.Placement
else:
group = obj.Group
svg = ""
for child in obj.Group:
for child in group:
svg += get_svg(child,
scale, linewidth, fontsize,
fillstyle, direction, linestyle,
color, linespacing, techdraw,
rotation, fillspaces, override)
if hidden_doc is not None:
try:
App.closeDocument(hidden_doc.Name)
except:
pass
return svg
vobj = _get_view_object(obj)
pathdata = []
svg = ""
linewidth = float(linewidth)/scale
if not override:
if hasattr(obj, "ViewObject") and hasattr(obj.ViewObject, "LineWidth"):
if hasattr(obj.ViewObject.LineWidth, "Value"):
lw = obj.ViewObject.LineWidth.Value
if vobj is not None and hasattr(vobj, "LineWidth"):
if hasattr(vobj.LineWidth, "Value"):
lw = vobj.LineWidth.Value
else:
lw = obj.ViewObject.LineWidth
lw = vobj.LineWidth
linewidth = lw * linewidth
fontsize = (float(fontsize)/scale)/2
@@ -484,20 +524,20 @@ def get_svg(obj,
if pc:
stroke = utils.get_rgb(pc)
# get line color
elif hasattr(obj, "ViewObject"):
if hasattr(obj.ViewObject, "LineColor"):
stroke = utils.get_rgb(obj.ViewObject.LineColor)
elif hasattr(obj.ViewObject, "TextColor"):
stroke = utils.get_rgb(obj.ViewObject.TextColor)
if hasattr(obj.ViewObject, "TextColor"):
tstroke = utils.get_rgb(obj.ViewObject.TextColor)
elif vobj is not None:
if hasattr(vobj, "LineColor"):
stroke = utils.get_rgb(vobj.LineColor)
elif hasattr(vobj, "TextColor"):
stroke = utils.get_rgb(vobj.TextColor)
if hasattr(vobj, "TextColor"):
tstroke = utils.get_rgb(vobj.TextColor)
lstyle = "none"
if override:
lstyle = get_line_style(linestyle, scale)
else:
if hasattr(obj, "ViewObject") and hasattr(obj.ViewObject, "DrawStyle"):
lstyle = get_line_style(obj.ViewObject.DrawStyle, scale)
if vobj is not None and hasattr(vobj, "DrawStyle"):
lstyle = get_line_style(vobj.DrawStyle, scale)
if not obj:
pass
@@ -515,13 +555,13 @@ def get_svg(obj,
_wrn("Export of dimensions to SVG is only available in GUI mode")
if App.GuiUp:
if obj.ViewObject.Proxy:
if hasattr(obj.ViewObject.Proxy, "circle"):
prx = obj.ViewObject.Proxy
if vobj.Proxy:
if hasattr(vobj.Proxy, "circle"):
prx = vobj.Proxy
# drawing arc
fill = "none"
if obj.ViewObject.DisplayMode == "World":
if vobj.DisplayMode == "World":
svg += get_path(obj, plane,
fill, pathdata, stroke, linewidth,
lstyle, fill_opacity=None,
@@ -543,14 +583,14 @@ def get_svg(obj,
edges=[prx.circle])
# drawing arrows
if hasattr(obj.ViewObject, "ArrowType"):
if hasattr(vobj, "ArrowType"):
p2 = get_proj(prx.p2, plane)
p3 = get_proj(prx.p3, plane)
arrowsize = obj.ViewObject.ArrowSize.Value/pointratio
arrowsize = vobj.ArrowSize.Value/pointratio
halfarrowlength = 2 * arrowsize
arrowangle = 2 * math.asin(halfarrowlength / prx.circle.Curve.Radius)
if hasattr(obj.ViewObject, "FlipArrows") \
and obj.ViewObject.FlipArrows:
if hasattr(vobj, "FlipArrows") \
and vobj.FlipArrows:
arrowangle = -arrowangle
_v1a = prx.circle.valueAt(prx.circle.FirstParameter
@@ -567,16 +607,16 @@ def get_svg(obj,
angle2 = -DraftVecUtils.angle(u2)
svg += get_arrow(obj,
obj.ViewObject.ArrowType,
vobj.ArrowType,
p2, arrowsize, stroke, linewidth,
angle1)
svg += get_arrow(obj,
obj.ViewObject.ArrowType,
vobj.ArrowType,
p3, arrowsize, stroke, linewidth,
angle2)
# drawing text
if obj.ViewObject.DisplayMode == "World":
if vobj.DisplayMode == "World":
_diff = (prx.circle.LastParameter
- prx.circle.FirstParameter)
t = prx.circle.tangentAt(prx.circle.FirstParameter
@@ -601,11 +641,11 @@ def get_svg(obj,
svg += svgtext.get_text(plane, techdraw,
tstroke, fontsize,
obj.ViewObject.FontName,
vobj.FontName,
tangle, tbase, prx.string)
elif utils.get_type(obj) == "Label":
if getattr(obj.ViewObject, "Line", True):
if getattr(vobj, "Line", True):
# Some Labels may have no Line property
# Draw multisegment line
proj_points = list(map(lambda x: get_proj(x, plane), obj.Points))
@@ -625,14 +665,14 @@ def get_svg(obj,
# Draw arrow.
# We are different here from 3D view
# if Line is set to 'off', no arrow is drawn
if hasattr(obj.ViewObject, "ArrowType") and len(obj.Points) >= 2:
if hasattr(vobj, "ArrowType") and len(obj.Points) >= 2:
last_segment = App.Vector(obj.Points[-1] - obj.Points[-2])
_v = get_proj(last_segment, plane)
angle = -DraftVecUtils.angle(_v) + math.pi
svg += get_arrow(obj,
obj.ViewObject.ArrowType,
vobj.ArrowType,
proj_points[-1],
obj.ViewObject.ArrowSize.Value/pointratio,
vobj.ArrowSize.Value/pointratio,
stroke, linewidth, angle)
if not App.GuiUp:
@@ -640,10 +680,10 @@ def get_svg(obj,
# print text
if App.GuiUp:
fontname = obj.ViewObject.FontName
fontname = vobj.FontName
position = get_proj(obj.Placement.Base, plane)
rotation = obj.Placement.Rotation
justification = obj.ViewObject.Justification
justification = vobj.Justification
text = obj.Text
svg += svgtext.get_text(plane, techdraw,
tstroke, fontsize, fontname,
@@ -656,17 +696,17 @@ def get_svg(obj,
_wrn("Export of texts to SVG is only available in GUI mode")
if App.GuiUp:
n = obj.ViewObject.FontName
n = vobj.FontName
if utils.get_type(obj) == "Annotation":
p = get_proj(obj.Position, plane)
r = obj.ViewObject.Rotation.getValueAs("rad")
r = vobj.Rotation.getValueAs("rad")
t = obj.LabelText
else: # DraftText (old) or Text (new, 0.19)
p = get_proj(obj.Placement.Base, plane)
r = obj.Placement.Rotation
t = obj.Text
j = obj.ViewObject.Justification
j = vobj.Justification
svg += svgtext.get_text(plane, techdraw,
tstroke, fontsize, n,
r, p, t,
@@ -678,8 +718,7 @@ def get_svg(obj,
_wrn("Export of axes to SVG is only available in GUI mode")
if App.GuiUp:
vobj = obj.ViewObject
fn = obj.ViewObject.FontName
fn = vobj.FontName
fill = 'none'
rad = vobj.BubbleSize.Value/2
n = 0
@@ -688,13 +727,13 @@ def get_svg(obj,
fill, pathdata, stroke, linewidth, lstyle,
fill_opacity=None,
edges=[e])
for t in obj.ViewObject.Proxy.getTextData():
for t in vobj.Proxy.getTextData():
pos = t[1].add(App.Vector(0,-fontsize/2,0))
svg += svgtext.get_text(plane, techdraw,
tstroke, fontsize, fn,
0.0, pos, t[0],
1.0, "center")
for b in obj.ViewObject.Proxy.getShapeData():
for b in vobj.Proxy.getShapeData():
if hasattr(b,"Curve") and isinstance(b.Curve,Part.Circle):
svg += get_circle(plane,
fill, stroke, linewidth, "none",
@@ -749,7 +788,6 @@ def get_svg(obj,
_wrn("Export of spaces to SVG is only available in GUI mode")
if App.GuiUp:
vobj = obj.ViewObject
if fillspaces and hasattr(obj, "Proxy"):
if not hasattr(obj.Proxy, "face"):
obj.Proxy.getArea(obj, notouch=True)
@@ -818,11 +856,10 @@ def get_svg(obj,
if obj.Shape.Faces:
if App.GuiUp:
try:
m = obj.ViewObject.DisplayMode
m = vobj.DisplayMode
except AttributeError:
m = None
vobj = obj.ViewObject
if m != "Wireframe":
if (fillstyle == "shape color") and hasattr(vobj,"ShapeColor"):
fill = utils.get_rgb(vobj.ShapeColor,
@@ -884,17 +921,17 @@ def get_svg(obj,
edges=obj.Shape.Edges)
if (App.GuiUp
and hasattr(obj.ViewObject, "EndArrow")
and obj.ViewObject.EndArrow
and hasattr(obj.ViewObject, "ArrowType")
and hasattr(vobj, "EndArrow")
and vobj.EndArrow
and hasattr(vobj, "ArrowType")
and len(obj.Shape.Vertexes) > 1):
p1 = get_proj(obj.Shape.Vertexes[-1].Point, plane)
p2 = get_proj(obj.Shape.Vertexes[-2].Point, plane)
angle = -DraftVecUtils.angle(p2 - p1)
arrowsize = obj.ViewObject.ArrowSize.Value/pointratio
arrowsize = vobj.ArrowSize.Value/pointratio
svg += get_arrow(obj,
obj.ViewObject.ArrowType,
vobj.ArrowType,
p1, arrowsize, stroke, linewidth, angle)
# techdraw expects bottom-to-top coordinates
@@ -904,6 +941,18 @@ def get_svg(obj,
return svg
def _get_view_object(obj):
if obj.isDerivedFrom("App::Link") \
and hasattr(obj, "ViewObject") \
and hasattr(obj.ViewObject, "OverrideMaterial") \
and not obj.ViewObject.OverrideMaterial \
and hasattr(obj.LinkedObject, "ViewObject"):
return obj.LinkedObject.ViewObject
if hasattr(obj, "ViewObject"):
return obj.ViewObject
return None
# Similar function as in view_layer.py
def _get_layer(obj):
"""Get the layer the object belongs to."""