AbdulElahGwaith's picture
Upload folder using huggingface_hub
985c397 verified
# SPDX-License-Identifier: LGPL-2.1-or-later
# -*- coding: utf8 -*-
# ***************************************************************************
# * Copyright (c) 2009 Yorik van Havre <yorik@uncreated.net> *
# * Copyright (c) 2018 George Shuklin (amarao) *
# * Copyright (c) 2020 Eliud Cabrera Castillo <e.cabrera-castillo@tum.de> *
# * *
# * This program is free software; you can redistribute it and/or modify *
# * it under the terms of the GNU Lesser General Public License (LGPL) *
# * as published by the Free Software Foundation; either version 2 of *
# * the License, or (at your option) any later version. *
# * for detail see the LICENCE text file. *
# * *
# * This program is distributed in the hope that it will be useful, *
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
# * GNU Library General Public License for more details. *
# * *
# * You should have received a copy of the GNU Library General Public *
# * License along with this program; if not, write to the Free Software *
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
# * USA *
# * *
# ***************************************************************************
"""Provides functions to return the SVG representation of various shapes."""
## @package svg
# \ingroup draftfunctions
# \brief Provides functions to return the SVG representation of shapes.
import math
import lazy_loader.lazy_loader as lz
import FreeCAD as App
import DraftVecUtils
import WorkingPlane
from draftfunctions import svgtext
from draftfunctions.svgshapes import get_proj, get_circle, get_path
from draftobjects import layer
from draftutils import params
from draftutils import utils
from draftutils.messages import _wrn, _err
# Delay import of module until first use because it is heavy
Part = lz.LazyLoader("Part", globals(), "Part")
DraftGeomUtils = lz.LazyLoader("DraftGeomUtils", globals(), "DraftGeomUtils")
## \addtogroup draftfunctions
# @{
def get_line_style(line_style, scale):
"""Return a linestyle scaled by a factor."""
style = None
if line_style == "Dashed":
style = params.get_param("svgDashedLine")
elif line_style == "Dashdot":
style = params.get_param("svgDashdotLine")
elif line_style == "Dotted":
style = params.get_param("svgDottedLine")
elif line_style:
if "," in line_style:
style = line_style
if style:
style = style.split(",")
try:
# scale dashes
style = ",".join([str(float(d) / scale) for d in style])
# print("lstyle ", style)
except Exception:
# TODO: trap only specific exception; what is the problem?
# Bad string specification?
return "none"
else:
return style
return "none"
def getLineStyle(linestyle, scale):
"""Return a Line style. DEPRECATED. Use get_line_style."""
utils.use_instead("get_line_style")
return get_line_style(linestyle, scale)
def get_pattern(pat):
"""Get an SVG pattern."""
patterns = utils.svg_patterns()
if pat in patterns:
return patterns[pat][0]
return ""
def getPattern(pat):
"""Get an SVG pattern. DEPRECATED."""
utils.use_instead("get_pattern")
return get_pattern(pat)
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 vobj is None:
return svg
_cx_cy_r = 'cx="{}" cy="{}" r="{}"'.format(point.x, point.y, arrowsize)
_rotate = "rotate({},{},{})".format(math.degrees(angle), point.x, point.y)
_transl = "translate({},{})".format(point.x, point.y)
_scale = "scale({size},{size})".format(size=arrowsize)
_style = 'style="stroke-miterlimit:4;stroke-dasharray:none;stroke-linecap:square"'
if arrowtype == "Circle":
svg += "<circle "
svg += _cx_cy_r + " "
svg += 'fill="{}" stroke="{}" '.format("none", color)
svg += 'style="stroke-width:{};'.format(linewidth)
svg += 'stroke-miterlimit:4;stroke-dasharray:none;stroke-linecap:square" '
svg += 'freecad:skip="1"'
svg += "/>\n"
elif arrowtype == "Dot":
svg += "<circle "
svg += _cx_cy_r + " "
svg += 'fill="{}" stroke="{}" '.format(color, "none")
svg += _style + " "
svg += 'freecad:skip="1"'
svg += "/>\n"
elif arrowtype == "Arrow":
svg += "<path "
svg += 'transform="'
svg += _rotate + " "
svg += _transl + " "
svg += _scale + '" '
svg += 'freecad:skip="1" '
svg += 'fill="{}" stroke="{}" '.format(color, "none")
svg += _style + " "
svg += 'd="M 0 0 L 4 1 L 4 -1 Z"'
svg += "/>\n"
elif arrowtype == "Tick":
svg += "<path "
svg += 'transform="'
svg += _rotate + " "
svg += _transl + " "
svg += _scale + '" '
svg += 'freecad:skip="1" '
svg += 'fill="{}" stroke="{}" '.format(color, "none")
svg += _style + " "
svg += 'd="M -1 -2 L 0 2 L 1 2 L 0 -2 Z"'
svg += "/>\n"
elif arrowtype == "Tick-2":
svg += "<line "
svg += 'transform="'
svg += "rotate({},{},{}) ".format(math.degrees(angle) + 45, point.x, point.y)
svg += _transl + '" '
svg += 'freecad:skip="1" '
svg += 'fill="{}" stroke="{}" '.format("none", color)
svg += 'style="stroke-dasharray:none;stroke-linecap:square;'
svg += 'stroke-width:{}" '.format(linewidth)
svg += 'x1="-{}" y1="0" '.format(2 * arrowsize)
svg += 'x2="{}" y2="0"'.format(2 * arrowsize)
svg += "/>\n"
elif arrowtype == "None":
svg += ""
else:
_wrn("getSVG: arrow type not implemented")
return svg
def getArrow(obj, arrowtype, point, arrowsize, color, linewidth, angle=0):
"""Get the SVG representation from an arrow. DEPRECATED."""
utils.use_instead("get_arrow")
return get_arrow(obj, arrowtype, point, arrowsize, color, linewidth, angle)
def get_overshoot(point, shootsize, color, linewidth, angle=0):
"""Get the SVG representation of a dimension line overshoot."""
svg = "<line "
svg += 'transform="'
svg += "rotate({},{},{}) ".format(math.degrees(angle), point.x, point.y)
svg += 'translate({},{})" '.format(point.x, point.y)
svg += 'freecad:skip="1" '
svg += 'fill="{}" stroke="{}" '.format("none", color)
svg += 'style="stroke-dasharray:none;stroke-linecap:square;'
svg += 'stroke-width:{}" '.format(linewidth)
svg += 'x1="0" y1="0" '
svg += 'x2="{}" y2="0"'.format(-1 * shootsize)
svg += "/>\n"
return svg
def getOvershoot(point, shootsize, color, linewidth, angle=0):
"""Get the SVG representation of a dimension line overshoot. DEPRECATED."""
utils.use_instead("get_overshoot")
return get_overshoot(point, shootsize, color, linewidth, angle)
def format_point(coords, action="L"):
"""Return a string with a formatted point."""
return "{action}{x},{y}".format(x=coords.x, y=coords.y, action=action)
def _svg_shape(svg, obj, plane, fillstyle, pathdata, stroke, linewidth, lstyle):
"""Return the SVG representation of a Part.Shape."""
if "#" in fillstyle:
fill = fillstyle
elif fillstyle == "shape color":
fill = "#888888"
elif fillstyle in ("none", None):
fill = "none"
else:
fill = "url(#" + fillstyle + ")"
svg += get_path(
obj,
plane,
fill,
pathdata,
stroke,
linewidth,
lstyle,
fill_opacity=None,
edges=obj.Edges,
pathname="",
)
return svg
def _svg_dimension(
obj, plane, scale, linewidth, fontsize, stroke, tstroke, pointratio, techdraw, rotation
):
"""Return the SVG representation of a linear dimension."""
if not App.GuiUp:
_wrn("'{}': SVG can only be generated " "in GUI mode".format(obj.Label))
return ""
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 ""
prx = vobj.Proxy
if not hasattr(prx, "p1"):
_err("'{}': doesn't have points, " "SVG cannot be generated".format(obj.Label))
return ""
ts = len(prx.string) * vobj.FontSize.Value / 4.0
rm = (prx.p3 - prx.p2).Length / 2.0 - ts
_diff32 = prx.p3 - prx.p2
_diff23 = prx.p2 - prx.p3
_v32 = DraftVecUtils.scaleTo(_diff32, rm)
_v23 = DraftVecUtils.scaleTo(_diff23, rm)
p2a = get_proj(prx.p2 + _v32, plane)
p2b = get_proj(prx.p3 + _v23, plane)
p1 = get_proj(prx.p1, plane)
p2 = get_proj(prx.p2, plane)
p3 = get_proj(prx.p3, plane)
p4 = get_proj(prx.p4, plane)
tbase = get_proj(prx.tbase, plane)
r = prx.textpos.rotation.getValue().getValue()
_rv = App.Rotation(r[0], r[1], r[2], r[3])
rv = _rv.multVec(App.Vector(1, 0, 0))
angle = -DraftVecUtils.angle(get_proj(rv, plane))
# angle = -DraftVecUtils.angle(p3.sub(p2))
svg = ""
nolines = False
if hasattr(vobj, "ShowLine"):
if not vobj.ShowLine:
nolines = True
# drawing lines
if not nolines:
svg += "<path "
if vobj.DisplayMode == "World":
tangle = angle
if tangle > math.pi / 2:
tangle = tangle - math.pi
# elif (tangle <= -math.pi/2) or (tangle > math.pi/2):
# tangle = tangle + math.pi
if rotation != 0:
# print("dim: tangle:", tangle,
# " rot: ", rotation,
# " text: ", prx.string)
if abs(tangle + math.radians(rotation)) < 0.0001:
tangle += math.pi
_v = App.Vector(0, 2.0 / scale, 0)
_rot = DraftVecUtils.rotate(_v, tangle)
tbase = tbase + _rot
if not nolines:
svg += 'd="M ' + str(p1.x) + " " + str(p1.y) + " "
svg += "L " + str(p2.x) + " " + str(p2.y) + " "
svg += "L " + str(p3.x) + " " + str(p3.y) + " "
svg += "L " + str(p4.x) + " " + str(p4.y) + '" '
else:
tangle = 0
if rotation != 0:
tangle = -math.radians(rotation)
tbase = tbase + App.Vector(0, -2.0 / scale, 0)
if not nolines:
svg += 'd="M ' + str(p1.x) + " " + str(p1.y) + " "
svg += "L " + str(p2.x) + " " + str(p2.y) + " "
svg += "L " + str(p2a.x) + " " + str(p2a.y) + " "
svg += "M " + str(p2b.x) + " " + str(p2b.y) + " "
svg += "L " + str(p3.x) + " " + str(p3.y) + " "
svg += "L " + str(p4.x) + " " + str(p4.y) + '" '
if not nolines:
svg += 'fill="none" stroke="'
svg += stroke + '" '
svg += 'stroke-width="' + str(linewidth) + ' px" '
svg += 'style="stroke-width:' + str(linewidth)
svg += ';stroke-miterlimit:4;stroke-dasharray:none;stroke-linecap:square" '
svg += 'freecad:basepoint1="' + str(p1.x) + " " + str(p1.y) + '" '
svg += 'freecad:basepoint2="' + str(p4.x) + " " + str(p4.y) + '" '
svg += 'freecad:dimpoint="' + str(p2.x) + " " + str(p2.y) + '"'
svg += "/>\n"
# drawing dimension and extension lines overshoots
if hasattr(vobj, "DimOvershoot") and vobj.DimOvershoot.Value:
shootsize = vobj.DimOvershoot.Value / pointratio
svg += get_overshoot(p2, shootsize, stroke, linewidth, angle)
svg += get_overshoot(p3, shootsize, stroke, linewidth, angle + math.pi)
if hasattr(vobj, "ExtOvershoot") and vobj.ExtOvershoot.Value:
shootsize = vobj.ExtOvershoot.Value / pointratio
shootangle = -DraftVecUtils.angle(p1 - p2)
svg += get_overshoot(p2, shootsize, stroke, linewidth, shootangle)
svg += get_overshoot(p3, shootsize, stroke, linewidth, shootangle)
# drawing arrows
if (
hasattr(vobj, "ArrowTypeStart")
and hasattr(vobj, "ArrowTypeEnd")
and hasattr(vobj, "ArrowSizeStart")
and hasattr(vobj, "ArrowSizeEnd")
):
if getattr(vobj, "FlipArrows", False):
angle = angle + math.pi
if getattr(vobj, "FlipText", False):
angle = angle + math.pi
svg += get_arrow(
obj,
vobj.ArrowTypeStart,
p2,
vobj.ArrowSizeStart.Value / pointratio,
stroke,
linewidth,
angle,
)
svg += get_arrow(
obj,
vobj.ArrowTypeEnd,
p3,
vobj.ArrowSizeEnd.Value / pointratio,
stroke,
linewidth,
angle + math.pi,
)
# drawing text
svg += svgtext.get_text(
plane, techdraw, tstroke, fontsize, vobj.FontName, tangle, tbase, prx.string
)
return svg
def get_svg(
obj,
scale=1,
linewidth=0.35,
fontsize=12,
fillstyle="shape color",
direction=None,
linestyle=None,
color=None,
linespacing=None,
techdraw=False,
rotation=0,
fillspaces=False,
override=True,
):
"""Return a string containing an SVG representation of the object.
Paramaeters
-----------
scale: float, optional
It defaults to 1.
It allows scaling line widths down, so they are resolution-independent.
linewidth: float, optional
It defaults to 0.35.
fontsize: float, optional
It defaults to 12, which is interpreted as `pt` unit (points).
It is used if the given object contains any text.
fillstyle: str, optional
It defaults to 'shape color'.
direction: Base::Vector3, optional
It defaults to `None`.
It is an arbitrary projection vector or a `WorkingPlane.PlaneBase`
instance.
linestyle: optional
It defaults to `None`.
color: optional
It defaults to `None`.
linespacing: float, optional
It defaults to `None`.
techdraw: bool, optional
It defaults to `False`.
If it is `True`, it sets some options for generating SVG strings
for displaying inside TechDraw.
rotation: float, optional
It defaults to 0.
fillspaces: bool, optional
It defaults to `False`.
override: bool, optional
It defaults to `True`.
"""
# If this is a group, recursively call this function to gather
# all the SVG strings from the contents of the group.
if (
obj.isDerivedFrom("App::DocumentObjectGroup")
or utils.get_type(obj) in ["Layer", "BuildingPart", "IfcGroup"]
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:
# Hidden doc hack:
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 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
# Handle Links to texts and dimensions. These Links do not have a Shape.
if obj.isDerivedFrom("App::Link") and obj.LinkedObject and not hasattr(obj, "Shape"):
# Hidden doc hack:
hidden_doc = App.newDocument(name="hidden", hidden=True, temp=True)
new = hidden_doc.copyObject(obj.LinkedObject, True)
if utils.get_type(new) in ("Dimension", "LinearDimension", "AngularDimension"):
new.Proxy.transform(new, obj.Placement)
elif utils.get_type(new) == "Text" or obj.LinkTransform:
new.Placement = obj.Placement * new.Placement
else:
new.Placement = obj.Placement
svg = get_svg(
new,
scale,
linewidth,
fontsize,
fillstyle,
direction,
linestyle,
color,
linespacing,
techdraw,
rotation,
fillspaces,
override,
)
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 vobj is not None and hasattr(vobj, "LineWidth"):
if hasattr(vobj.LineWidth, "Value"):
lw = vobj.LineWidth.Value
else:
lw = vobj.LineWidth
linewidth = lw * linewidth
fontsize = (float(fontsize) / scale) / 2
if linespacing:
linespacing = float(linespacing) / scale
else:
linespacing = 0.5
# print(obj.Label, "line spacing", linespacing, "scale", scale)
# The number of times the dots are smaller than the arrow size
pointratio = 0.75
plane = None
if direction:
if isinstance(direction, App.Vector):
if direction != App.Vector(0, 0, 0):
plane = WorkingPlane.PlaneBase()
plane.align_to_point_and_axis_svg(
App.Vector(0, 0, 0), direction.negative().negative(), 0
)
else:
raise ValueError("'direction' cannot be: Vector(0, 0, 0)")
elif isinstance(direction, WorkingPlane.PlaneBase):
plane = direction
stroke = "#000000"
tstroke = stroke
if color and override:
if "#" in color:
stroke = color
else:
stroke = utils.get_rgb(color)
tstroke = stroke
elif App.GuiUp:
# find print color
pc = get_print_color(obj)
if pc:
stroke = utils.get_rgb(pc)
# get line color
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 vobj is not None and hasattr(vobj, "DrawStyle"):
lstyle = get_line_style(vobj.DrawStyle, scale)
if not obj:
pass
elif isinstance(obj, Part.Shape):
svg = _svg_shape(svg, obj, plane, fillstyle, pathdata, stroke, linewidth, lstyle)
elif utils.get_type(obj) in ["Dimension", "LinearDimension"] or (
utils.get_type(obj) == "IfcAnnotation" and obj.ObjectType == "DIMENSION"
):
svg = _svg_dimension(
obj, plane, scale, linewidth, fontsize, stroke, tstroke, pointratio, techdraw, rotation
)
elif utils.get_type(obj) == "AngularDimension":
if not App.GuiUp:
_wrn("Export of dimensions to SVG is only available in GUI mode")
if App.GuiUp:
if vobj.Proxy:
if hasattr(vobj.Proxy, "circle"):
prx = vobj.Proxy
# drawing arc
fill = "none"
if vobj.DisplayMode == "World":
svg += get_path(
obj,
plane,
fill,
pathdata,
stroke,
linewidth,
lstyle,
fill_opacity=None,
edges=[prx.circle],
)
else:
if hasattr(prx, "circle1"):
svg += get_path(
obj,
plane,
fill,
pathdata,
stroke,
linewidth,
lstyle,
fill_opacity=None,
edges=[prx.circle1],
)
svg += get_path(
obj,
plane,
fill,
pathdata,
stroke,
linewidth,
lstyle,
fill_opacity=None,
edges=[prx.circle2],
)
else:
svg += get_path(
obj,
plane,
fill,
pathdata,
stroke,
linewidth,
lstyle,
fill_opacity=None,
edges=[prx.circle],
)
# drawing arrows
if (
hasattr(vobj, "ArrowTypeStart")
and hasattr(vobj, "ArrowTypeEnd")
and hasattr(vobj, "ArrowSizeStart")
and hasattr(vobj, "ArrowSizeEnd")
):
p2 = get_proj(prx.p2, plane)
p3 = get_proj(prx.p3, plane)
arrowsizestart = vobj.ArrowSizeStart.Value / pointratio
halfstartarrowlength = 2 * arrowsizestart
startarrowangle = 2 * math.asin(
halfstartarrowlength / prx.circle.Curve.Radius
)
arrowsizeend = vobj.ArrowSizeEnd.Value / pointratio
halfendarrowlength = 2 * arrowsizeend
endarrowangle = 2 * math.asin(halfendarrowlength / prx.circle.Curve.Radius)
if hasattr(vobj, "FlipArrows") and vobj.FlipArrows:
startarrowangle = -startarrowangle
endarrowangle = -endarrowangle
_v1a = prx.circle.valueAt(prx.circle.FirstParameter + startarrowangle)
_v1b = prx.circle.valueAt(prx.circle.FirstParameter)
_v2a = prx.circle.valueAt(prx.circle.LastParameter - endarrowangle)
_v2b = prx.circle.valueAt(prx.circle.LastParameter)
u1 = get_proj(_v1a - _v1b, plane)
u2 = get_proj(_v2a - _v2b, plane)
angle1 = -DraftVecUtils.angle(u1)
angle2 = -DraftVecUtils.angle(u2)
svg += get_arrow(
obj, vobj.ArrowTypeStart, p2, arrowsizestart, stroke, linewidth, angle1
)
svg += get_arrow(
obj, vobj.ArrowTypeEnd, p3, arrowsizeend, stroke, linewidth, angle2
)
# drawing text
if vobj.DisplayMode == "World":
_diff = prx.circle.LastParameter - prx.circle.FirstParameter
t = prx.circle.tangentAt(prx.circle.FirstParameter + _diff / 2.0)
t = get_proj(t, plane)
tangle = -DraftVecUtils.angle(t)
if (tangle <= -math.pi / 2) or (tangle > math.pi / 2):
tangle = tangle + math.pi
_diff = prx.circle.LastParameter - prx.circle.FirstParameter
_va = prx.circle.valueAt(prx.circle.FirstParameter + _diff / 2.0)
tbase = get_proj(_va, plane)
_v = App.Vector(0, 2.0 / scale, 0)
tbase = tbase + DraftVecUtils.rotate(_v, tangle)
# print(tbase)
else:
tangle = 0
tbase = get_proj(prx.tbase, plane)
svg += svgtext.get_text(
plane, techdraw, tstroke, fontsize, vobj.FontName, tangle, tbase, prx.string
)
elif utils.get_type(obj) == "Label":
if not App.GuiUp:
_wrn("Export of texts to SVG is only available in GUI mode")
if App.GuiUp:
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))
path_dir_list = [format_point(proj_points[0], action="M")]
path_dir_list += map(format_point, proj_points[1:])
path_dir_str = " ".join(path_dir_list)
svg_path = "<path "
svg_path += 'fill="none" '
svg_path += 'stroke="{}" '.format(stroke)
svg_path += 'stroke-width="{}" '.format(linewidth)
svg_path += 'stroke-linecap="square" '
svg_path += 'd="{}"'.format(path_dir_str)
svg_path += "/>"
svg += svg_path
# Draw arrow.
# We are different here from 3D view
# if Line is set to 'off', no arrow is drawn
if hasattr(vobj, "ArrowTypeStart") and (
hasattr(vobj, "ArrowSizeStart") and len(obj.Points) > 1
):
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,
vobj.ArrowTypeStart,
proj_points[-1],
vobj.ArrowSizeStart.Value / pointratio,
stroke,
linewidth,
angle,
)
fontname = vobj.FontName
position = get_proj(obj.Placement.Base, plane)
rotation = obj.Placement.Rotation
justification = vobj.Justification
text = obj.Text
svg += svgtext.get_text(
plane,
techdraw,
tstroke,
fontsize,
fontname,
rotation,
position,
text,
linespacing,
justification,
)
elif utils.get_type(obj) in ["Annotation", "DraftText", "Text"] or (
utils.get_type(obj) == "IfcAnnotation" and obj.ObjectType == "TEXT"
):
# returns an svg representation of a document annotation
if not App.GuiUp:
_wrn("Export of texts to SVG is only available in GUI mode")
if App.GuiUp:
n = vobj.FontName
if utils.get_type(obj) == "Annotation":
p = get_proj(obj.Position, plane)
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 = vobj.Justification
svg += svgtext.get_text(plane, techdraw, tstroke, fontsize, n, r, p, t, linespacing, j)
elif utils.get_type(obj) == "Axis":
# returns the SVG representation of an Arch Axis system
if not App.GuiUp:
_wrn("Export of axes to SVG is only available in GUI mode")
if App.GuiUp:
fn = vobj.FontName
fill = "none"
rad = vobj.BubbleSize.Value / 2
n = 0
for e in obj.Shape.Edges:
svg += get_path(
obj,
plane,
fill,
pathdata,
stroke,
linewidth,
lstyle,
fill_opacity=None,
edges=[e],
)
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 vobj.Proxy.getShapeData():
if hasattr(b, "Curve") and isinstance(b.Curve, Part.Circle):
svg += get_circle(plane, fill, stroke, linewidth, "none", b)
else:
sfill = stroke
svg += get_path(
obj,
plane,
sfill,
pathdata,
stroke,
linewidth,
"none",
fill_opacity=None,
edges=b.Edges,
)
elif utils.get_type(obj) == "Pipe":
fill = stroke
if obj.Base and obj.Diameter:
svg += get_path(
obj,
plane,
fill,
pathdata,
stroke,
linewidth,
lstyle,
fill_opacity=None,
edges=obj.Base.Shape.Edges,
)
for f in obj.Shape.Faces:
if len(f.Edges) == 1:
if isinstance(f.Edges[0].Curve, Part.Circle):
svg += get_circle(plane, fill, stroke, linewidth, lstyle, f.Edges[0])
elif utils.get_type(obj) == "Rebar":
fill = "none"
basewire = obj.Base.Shape.Wires[0].copy()
# Not applying rounding because the results are not correct
# if hasattr(obj, "Rounding") and obj.Rounding:
# basewire = DraftGeomUtils.filletWire(
# basewire, obj.Rounding * obj.Diameter.Value
# )
wires = []
for placement in obj.PlacementList:
wire = basewire.copy()
wire.Placement = placement.multiply(basewire.Placement)
wires.append(wire)
svg += get_path(
obj, plane, fill, pathdata, stroke, linewidth, lstyle, fill_opacity=None, wires=wires
)
elif utils.get_type(obj) == "PipeConnector":
pass
elif utils.get_type(obj) == "Space":
fill_opacity = 1
# returns an SVG fragment for the text of a space
if not App.GuiUp:
_wrn("Export of spaces to SVG is only available in GUI mode")
if App.GuiUp:
if fillspaces and hasattr(obj, "Proxy"):
if not hasattr(obj.Proxy, "face"):
obj.Proxy.getArea(obj, notouch=True)
if hasattr(obj.Proxy, "face"):
# setting fill
if App.GuiUp and hasattr(vobj, "ShapeColor"):
fill = utils.get_rgb(vobj.ShapeColor, testbw=False)
fill_opacity = 1 - vobj.Transparency / 100.0
else:
fill = "#888888"
svg += get_path(
obj,
plane,
fill,
pathdata,
stroke,
linewidth,
lstyle,
fill_opacity=fill_opacity,
wires=[obj.Proxy.face.OuterWire],
)
c = utils.get_rgb(vobj.TextColor)
n = vobj.FontName
a = 0
if rotation != 0:
a = math.radians(rotation)
t1 = vobj.Proxy.text1.string.getValues()
t2 = vobj.Proxy.text2.string.getValues()
scale = vobj.FirstLine.Value / vobj.FontSize.Value
f1 = fontsize * scale
if round(plane.axis.getAngle(App.Vector(0, 0, 1)), 2) not in [0, 3.14]:
# if not in XY view, place the label at center
p2 = obj.Shape.CenterOfMass
else:
_v = vobj.Proxy.coords.translation.getValue().getValue()
p2 = obj.Placement.multVec(App.Vector(_v))
_h = vobj.Proxy.header.translation.getValue().getValue()
lspc = App.Vector(_h)
p1 = p2 + lspc
j = vobj.TextAlign
t3 = svgtext.get_text(
plane, techdraw, c, f1, n, a, get_proj(p1, plane), t1, linespacing, j, flip=True
)
svg += t3
if t2:
ofs = App.Vector(0, -lspc.Length, 0)
if a:
Z = App.Vector(0, 0, 1)
ofs = App.Rotation(Z, -rotation).multVec(ofs)
t4 = svgtext.get_text(
plane,
techdraw,
c,
fontsize,
n,
a,
get_proj(p1, plane).add(ofs),
t2,
linespacing,
j,
flip=True,
)
svg += t4
elif hasattr(obj, "Shape"):
# In the past we tested for a Part Feature
# elif obj.isDerivedFrom('Part::Feature'):
#
# however, this doesn't work for App::Links; instead we
# test for a 'Shape'. All Part::Features should have a Shape,
# and App::Links can have one as well.
if obj.Shape.isNull():
return ""
fill_opacity = 1
# setting fill
if obj.Shape.Faces:
if App.GuiUp:
try:
m = vobj.DisplayMode
except AttributeError:
m = None
if m != "Wireframe":
if (fillstyle == "shape color") and hasattr(vobj, "ShapeColor"):
fill = utils.get_rgb(vobj.ShapeColor, testbw=False)
fill_opacity = 1 - vobj.Transparency / 100.0
elif fillstyle in ("none", None):
fill = "none"
else:
fill = "url(#" + fillstyle + ")"
svg += get_pattern(fillstyle)
else:
fill = "none"
else:
fill = "#888888"
else:
fill = "none"
if len(obj.Shape.Vertexes) > 1:
wiredEdges = []
if obj.Shape.Faces:
for i, f in enumerate(obj.Shape.Faces):
# place outer wire first
wires = [f.OuterWire]
wires.extend([w for w in f.Wires if w.hashCode() != f.OuterWire.hashCode()])
svg += get_path(
obj,
plane,
fill,
pathdata,
stroke,
linewidth,
lstyle,
fill_opacity=fill_opacity,
wires=f.Wires,
pathname="%s_f%04d" % (obj.Name, i),
)
wiredEdges.extend(f.Edges)
else:
for i, w in enumerate(obj.Shape.Wires):
svg += get_path(
obj,
plane,
fill,
pathdata,
stroke,
linewidth,
lstyle,
fill_opacity=fill_opacity,
edges=w.Edges,
pathname="%s_w%04d" % (obj.Name, i),
)
wiredEdges.extend(w.Edges)
if len(wiredEdges) != len(obj.Shape.Edges):
fill = "none" # Required if obj has a face. Edges processed here have no face.
def get_edge_descriptor(edge):
return (
str(edge.Curve),
str(edge.Vertexes[0].Point),
str(edge.Vertexes[-1].Point),
)
wiredEdgesSet = set([get_edge_descriptor(e) for e in wiredEdges])
for i, e in enumerate(obj.Shape.Edges):
if get_edge_descriptor(e) not in wiredEdgesSet:
svg += get_path(
obj,
plane,
fill,
pathdata,
stroke,
linewidth,
lstyle,
fill_opacity=fill_opacity,
edges=[e],
pathname="%s_nwe%04d" % (obj.Name, i),
)
else:
# closed circle or spline
if obj.Shape.Edges:
if isinstance(obj.Shape.Edges[0].Curve, Part.Circle):
svg = get_circle(plane, fill, stroke, linewidth, lstyle, obj.Shape.Edges[0])
else:
svg = get_path(
obj,
plane,
fill,
pathdata,
stroke,
linewidth,
lstyle,
fill_opacity=fill_opacity,
edges=obj.Shape.Edges,
)
if (
App.GuiUp
and hasattr(vobj, "ArrowTypeStart")
and hasattr(vobj, "ArrowTypeEnd")
and hasattr(vobj, "ArrowSizeStart")
and hasattr(vobj, "ArrowSizeEnd")
and len(obj.Shape.Vertexes) > 1
):
# Draft_Wire
p1 = get_proj(obj.Shape.Vertexes[0].Point, plane)
p2 = get_proj(obj.Shape.Vertexes[1].Point, plane)
svg += get_arrow(
obj,
vobj.ArrowTypeStart,
p1,
vobj.ArrowSizeStart.Value / pointratio,
stroke,
linewidth,
-DraftVecUtils.angle(p2 - p1),
)
p1 = get_proj(obj.Shape.Vertexes[-1].Point, plane)
p2 = get_proj(obj.Shape.Vertexes[-2].Point, plane)
svg += get_arrow(
obj,
vobj.ArrowTypeEnd,
p1,
vobj.ArrowSizeEnd.Value / pointratio,
stroke,
linewidth,
-DraftVecUtils.angle(p2 - p1),
)
# techdraw expects bottom-to-top coordinates
if techdraw:
svg = '<g transform ="scale(1,-1)">\n ' + svg + "</g>\n"
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
def get_print_color(obj):
"""Return the print color of the parent layer, if available."""
# Layers are not in the Inlist of obj because a layer's Group is App::PropertyLinkListHidden:
lyr = layer.get_layer(obj)
if lyr is None:
return None
if lyr.ViewObject.UsePrintColor:
return lyr.ViewObject.LinePrintColor
return None
def getSVG(
obj,
scale=1,
linewidth=0.35,
fontsize=12,
fillstyle="shape color",
direction=None,
linestyle=None,
color=None,
linespacing=None,
techdraw=False,
rotation=0,
fillSpaces=False,
override=True,
):
"""Return SVG string of the object. DEPRECATED. Use 'get_svg'."""
utils.use_instead("get_svg")
return get_svg(
obj,
scale=scale,
linewidth=linewidth,
fontsize=fontsize,
fillstyle=fillstyle,
direction=direction,
linestyle=linestyle,
color=color,
linespacing=linespacing,
techdraw=techdraw,
rotation=rotation,
fillspaces=fillSpaces,
override=override,
)
## @}