Skip to content

Instantly share code, notes, and snippets.

@amrit3701
Last active June 12, 2020 16:23
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save amrit3701/8f67c8ea06c74a64bca08a0a48560556 to your computer and use it in GitHub Desktop.
Save amrit3701/8f67c8ea06c74a64bca08a0a48560556 to your computer and use it in GitHub Desktop.
Create an SVG file of cube with its dimensions using FreeCAD

This example shows that how to produce SVG file of cube with its dimensions in FreeCAD (compiled without GUI).

Output SVG file: screenshot

""" Handles dimensions of AHU casing."""
import FreeCAD
import Draft
def create_boundary_dimensions(obj,
dis_bw_obj_and_dim=100):
""" Create dimensions of length, width and height of given object."""
ldimline = FreeCAD.Vector(0,
obj.Shape.BoundBox.YMin - dis_bw_obj_and_dim,
obj.Shape.BoundBox.ZMin)
ldim = Draft.makeDimension(obj.Shape.BoundBox.getPoint(4),
obj.Shape.BoundBox.getPoint(5),
ldimline)
wdimline = FreeCAD.Vector(obj.Shape.BoundBox.XMax + dis_bw_obj_and_dim,
0,
obj.Shape.BoundBox.ZMin)
wdim = Draft.makeDimension(obj.Shape.BoundBox.getPoint(5),
obj.Shape.BoundBox.getPoint(6),
wdimline)
hdimline = FreeCAD.Vector(obj.Shape.BoundBox.XMin - dis_bw_obj_and_dim,
obj.Shape.BoundBox.YMin,
0)
hdim = Draft.makeDimension(obj.Shape.BoundBox.getPoint(0),
obj.Shape.BoundBox.getPoint(4),
hdimline)
FreeCAD.ActiveDocument.recompute()
return ldim, wdim, hdim
""" Export FreeCAD objects to SVG."""
import FreeCAD
from .get_svg import get_svg_of_dimension
def get_svg_representation_of_obj(obj,
direction=FreeCAD.Vector(1, -1, 1), # Isometric
scale=1,
rotation=60,
line_width=1,
hidden_line_width=.5,
show_hidden_line=False):
""" Get SVG representation of a given object."""
if hasattr(obj, 'Label'):
view = FreeCAD.ActiveDocument.addObject('Drawing::FeatureViewPart', 'View_' + obj.Label)
else:
view = FreeCAD.ActiveDocument.addObject('Drawing::FeatureViewPart', 'View')
view.Source = obj
view.Direction = direction
view.Rotation = rotation
view.Scale = scale
view.LineWidth = line_width
view.HiddenWidth = hidden_line_width
view.ShowHiddenLines = show_hidden_line
# FreeCAD.ActiveDocument.recompute()
view.recompute()
svg = view.ViewResult
# FreeCAD.ActiveDocument.removeObject(view.Name)
return svg
def export_svg(objs,
direction=FreeCAD.Vector(1, -1, 1), # Isometric
scale=1,
rotation=60,
line_width=1,
hidden_line_width=.5,
show_hidden_line=False,
dims=None,
file_path=None):
""" Exports FreeCAD objects to SVG.
If file_path is None then it will return a SVG string
otherwise it will save content to a given file_path."""
svg = '''<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">'''
# TODO: Calculate viewbox according to object size.
svg += '''<svg viewBox="-250 -400 1000 1000" xmlns="http://www.w3.org/2000/svg" xmlns:freecad="FreeCAD" version="1.1">'''
for obj in objs:
svg += get_svg_representation_of_obj(obj,
direction,
scale,
rotation,
line_width,
hidden_line_width,
show_hidden_line)
if dims:
svg += get_svg_path_dimensions(dims, direction, scale, rotation, line_width, 75)
svg += '''</svg>'''
if file_path:
with open(file_path, 'w') as f:
f.write(svg)
f.close()
else:
return svg
def get_svg_path_dimensions(dims,
direction = FreeCAD.Vector(1, -1, 1),
scale=1,
rotation=60,
line_width=5,
fontsize=10):
""" Get SVG path of given dimensions."""
svg_path = '''<g transform = "rotate({}, 0, 0) translate(0, 0) scale({},{})">'''.format(rotation, scale, scale)
for dim in dims:
svg_path += get_svg_of_dimension(obj=dim,
direction=FreeCAD.Vector(1, -1, 1),
rotation=60,
linewidth=line_width,
fontsize=fontsize,
techdraw=True)
svg_path += '''</g>'''
return svg_path
""" Export dimensions into SVG."""
import math
import FreeCAD
import DraftVecUtils
import WorkingPlane
import Part
import DraftGeomUtils
from Draft import getType, getrgb
def get_svg_of_dimension(obj,
scale=1,
linewidth=0.35,
fontsize=12,
fillstyle='shape color',
direction=None,
linestyle=None,
color='#0000FF',
linespacing=None,
techdraw=False,
rotation=0):
""" Returns a string containing a SVG representation of the given object,
with the given linewidth and fontsize (used if the given object contains
any text). You can also supply an arbitrary projection vector. the
scale parameter allows to scale linewidths down, so they are resolution-independant."""
# if this is a group, gather all the svg views of its children
if hasattr(obj, 'isDerivedFrom'):
if obj.isDerivedFrom('App::DocumentObjectGroup'):
svg = ""
for child in obj.Group:
svg += get_svg_of_dimension(child,
scale,
linewidth,
fontsize,
fillstyle,
direction,
linestyle,
color,
linespacing,
techdraw)
return svg
pathdata = []
svg = ""
linewidth = float(linewidth) / scale
fontsize = (float(fontsize) / scale) / 2
if linespacing:
linespacing = float(linespacing) / scale
else:
linespacing = 0.5
pointratio = 0.75 # the number of times the dots are smaller than the arrow size
plane = None
if direction:
if isinstance(direction, FreeCAD.Vector):
if direction != FreeCAD.Vector(0, 0, 0):
plane = WorkingPlane.plane()
plane.alignToPointAndAxis_SVG(FreeCAD.Vector(0, 0, 0), direction.negative().negative(), 0)
elif isinstance(direction, WorkingPlane.plane):
plane = direction
stroke = '#000000'
if color:
if '#' in color:
stroke = color
else:
stroke = getrgb(color)
def get_line_style():
"""Returns a linestyle."""
p = FreeCAD.ParamGet('User parameter:BaseApp/Preferences/Mod/Draft')
l = None
if linestyle == 'Dashed':
l = p.GetString('svgDashedLine', '0.09,0.05')
elif linestyle == 'Dashdot':
l = p.GetString('svgDashdotLine', '0.09,0.05,0.02,0.05')
elif linestyle == 'Dotted':
l = p.GetString('svgDottedLine', '0.02,0.02')
elif linestyle:
if ',' in linestyle:
l = linestyle
if l:
l = l.split(',')
try:
# scale dashes
l = ','.join([str(float(d) / scale) for d in l])
except:
return 'none'
else:
return l
return 'none'
def get_proj(vec):
if not plane:
return vec
nx = DraftVecUtils.project(vec, plane.u)
lx = nx.Length
if abs(nx.getAngle(plane.u)) > 0.1:
lx = -lx
ny = DraftVecUtils.project(vec, plane.v)
ly = ny.Length
if abs(ny.getAngle(plane.v)) > 0.1:
ly = -ly
#if techdraw: buggy - we now simply do it at the end
# ly = -ly
return FreeCAD.Vector(lx, ly, 0)
def get_discretized(edge):
ml = FreeCAD.ParamGet('User parameter:BaseApp/Preferences/Mod/Draft').GetFloat('svgDiscretization', 10.0)
if ml == 0:
ml = 10
d = int(edge.Length / ml)
if d == 0:
d = 1
edata = ""
for i in range(d + 1):
v = get_proj(edge.valueAt(edge.FirstParameter + ((float(i) / d) * (edge.LastParameter - edge.FirstParameter))))
if not edata:
edata += 'M ' + str(v.x) +' '+ str(v.y) + ' '
else:
edata += 'L ' + str(v.x) +' '+ str(v.y) + ' '
return edata
def get_pattern(pat):
if pat in svgpatterns():
return svgpatterns()[pat][0]
return ''
def get_path(edges=[], wires=[], pathname=None):
svg = "<path "
if pathname is None:
svg += 'id="%s" ' % obj.Name
elif pathname != "":
svg += 'id="%s" ' % pathname
svg += ' d="'
if not wires:
egroups = Part.sortEdges(edges)
else:
egroups = []
for w in wires:
w1 = w.copy()
w1.fixWire()
egroups.append(Part.__sortEdges__(w1.Edges))
for egroupindex, edges in enumerate(egroups):
edata = ""
vs = () # skipped for the first edge
for edgeindex, e in enumerate(edges):
previousvs = vs
# vertexes of an edge (reversed if needed)
vs = e.Vertexes
if previousvs:
if (vs[0].Point - previousvs[-1].Point).Length > 1e-6:
vs.reverse()
if edgeindex == 0:
v = get_proj(vs[0].Point)
edata += 'M '+ str(v.x) +' '+ str(v.y) + ' '
else:
if (vs[0].Point - previousvs[-1].Point).Length > 1e-6:
raise ValueError('edges not ordered')
iscircle = DraftGeomUtils.geomType(e) == 'Circle'
isellipse = DraftGeomUtils.geomType(e) == 'Ellipse'
if iscircle or isellipse:
if hasattr(FreeCAD, 'DraftWorkingPlane'):
drawing_plane_normal = FreeCAD.DraftWorkingPlane.axis
else:
drawing_plane_normal = FreeCAD.Vector(0, 0, 1)
if plane:
drawing_plane_normal = plane.axis
c = e.Curve
if round(c.Axis.getAngle(drawing_plane_normal), 2) in [0, 3.14]:
occversion = Part.OCC_VERSION.split('.')
done = False
if (occversion[0] >= 7) and (occversion[1] >= 1):
# if using occ >= 7.1, use HLR algorithm
import Drawing
snip = Drawing.projectToSVG(e,drawing_plane_normal)
if snip:
try:
a = "A " + snip.split("path d=\"")[1].split("\"")[0].split("A")[1]
except:
pass
else:
edata += a
done = True
if not done:
if len(e.Vertexes) == 1 and iscircle: # complete curve
svg = get_circle(e)
return svg
elif len(e.Vertexes) == 1 and isellipse:
endpoints = (get_proj(c.value((c.LastParameter - \
c.FirstParameter) / 2.0)), \
get_proj(vs[-1].Point))
else:
endpoints = (get_proj(vs[-1].Point),)
# arc
if iscircle:
rx = ry = c.Radius
rot = 0
else: # ellipse
rx = c.MajorRadius
ry = c.MinorRadius
rot = math.degrees(c.AngleXU * (c.Axis * \
FreeCAD.Vector(0, 0, 1)))
if rot > 90:
rot -=180
if rot < -90:
rot += 180
# be careful with the sweep flag
flag_large_arc = (((e.ParameterRange[1] - \
e.ParameterRange[0]) / math.pi) % 2) > 1
# flag_sweep = (c.Axis * drawing_plane_normal >= 0) \
# == (e.LastParameter > e.FirstParameter)
# == (e.Orientation == "Forward")
# other method: check the direction of the angle between tangents
t1 = e.tangentAt(e.FirstParameter)
t2 = e.tangentAt(e.FirstParameter + (e.LastParameter - e.FirstParameter) / 10)
flag_sweep = (DraftVecUtils.angle(t1, t2, drawing_plane_normal) < 0)
for v in endpoints:
edata += 'A %s %s %s %s %s %s %s ' % \
(str(rx), str(ry), str(rot),\
str(int(flag_large_arc)),\
str(int(flag_sweep)), str(v.x), str(v.y))
else:
edata += get_discretized(e)
elif DraftGeomUtils.geomType(e) == 'Line':
v = get_proj(vs[-1].Point)
edata += 'L ' + str(v.x) + ' ' + str(v.y) + ' '
else:
bspline = e.Curve.toBSpline(e.FirstParameter, e.LastParameter)
if bspline.Degree > 3 or bspline.isRational():
try:
bspline = bspline.approximateBSpline(0.05, 50, 3, 'C0')
except RuntimeError:
print('Debug: unable to approximate bspline')
if bspline.Degree <= 3 and not bspline.isRational():
for bezierseg in bspline.toBezier():
if bezierseg.Degree>3: # should not happen
raise AssertionError
elif bezierseg.Degree == 1:
edata += 'L '
elif bezierseg.Degree == 2:
edata += 'Q '
elif bezierseg.Degree == 3:
edata += 'C '
for pole in bezierseg.getPoles()[1:]:
v = get_proj(pole)
edata += str(v.x) + ' ' + str(v.y) + ' '
else:
print('Debug: one edge (hash ', e.hashCode(), \
') has been discretized with parameter 0.1')
for linepoint in bspline.discretize(0.1)[1:]:
v = get_proj(linepoint)
edata += 'L ' + str(v.x) + ' ' + str(v.y) + ' '
if fill != 'none':
edata += 'Z '
if edata in pathdata:
# do not draw a path on another identical path
return ''
else:
svg += edata
pathdata.append(edata)
svg += '" '
svg += 'stroke="' + stroke + '" '
svg += 'stroke-width="' + str(linewidth) + ' px" '
svg += 'style="stroke-width:'+ str(linewidth)
svg += ';stroke-miterlimit:4'
svg += ';stroke-dasharray:' + lstyle
svg += ';fill:' + fill
try:
svg += ';fill-opacity:' + str(fill_opacity)
except NameError:
pass
svg += ';fill-rule: evenodd "'
svg += '/>\n'
return svg
def get_circle(edge):
cen = get_proj(edge.Curve.Center)
rad = edge.Curve.Radius
if hasattr(FreeCAD, 'DraftWorkingPlane'):
drawing_plane_normal = FreeCAD.DraftWorkingPlane.axis
else:
drawing_plane_normal = FreeCAD.Vector(0, 0, 1)
if plane:
drawing_plane_normal = plane.axis
if round(edge.Curve.Axis.getAngle(drawing_plane_normal), 2) == 0:
# perpendicular projection: circle
svg = '<circle cx="' + str(cen.x)
svg += '" cy="' + str(cen.y)
svg += '" r="' + str(rad) + '" '
else:
# any other projection: ellipse
svg = '<path d="'
svg += get_discretized(edge)
svg += '" '
svg += 'stroke="' + stroke + '" '
svg += 'stroke-width="' + str(linewidth) + ' px" '
svg += 'style="stroke-width:'+ str(linewidth)
svg += ';stroke-miterlimit:4'
svg += ';stroke-dasharray:' + lstyle
svg += ';fill:' + fill + '"'
svg += '/>\n'
return svg
def get_ellipse(edge):
cen = get_proj(edge.Curve.Center)
mir = edge.Curve.MinorRadius
mar = edge.Curve.MajorRadius
svg = '<ellipse cx="' + str(cen.x)
svg += '" cy="' + str(cen.y)
svg += '" rx="' + str(mar)
svg += '" ry="' + str(mir) + '" '
svg += 'stroke="' + stroke + '" '
svg += 'stroke-width="' + str(linewidth) + ' px" '
svg += 'style="stroke-width:' + str(linewidth)
svg += ';stroke-miterlimit:4'
svg += ';stroke-dasharray:' + lstyle
svg += ';fill:' + fill + '"'
svg += '/>\n'
return svg
def get_arrow(arrowtype, point, arrowsize, color, linewidth, angle=0):
svg = ""
if arrowtype == 'Circle':
svg += '<circle cx="' + str(point.x) + '" cy="' + str(point.y)
svg += '" r="' + str(arrowsize) + '" '
svg += 'fill="none" stroke="' + color + '" '
svg += 'style="stroke-width:'+ str(linewidth) + ';stroke-miterlimit:4;stroke-dasharray:none" '
svg += 'freecad:skip="1"'
svg += '/>\n'
elif arrowtype == 'Dot':
svg += '<circle cx="' + str(point.x) + '" cy="' + str(point.y)
svg += '" r="' + str(arrowsize) + '" '
svg += 'fill="' + color +'" stroke="none" '
svg += 'style="stroke-miterlimit:4;stroke-dasharray:none" '
svg += 'freecad:skip="1"'
svg += '/>\n'
elif arrowtype == 'Arrow':
svg += '<path transform="rotate(' + str(math.degrees(angle))
svg += ',' + str(point.x) + ',' + str(point.y) + ') '
svg += 'translate(' + str(point.x) + ',' + str(point.y) + ') '
svg += 'scale(' + str(arrowsize) + ',' + str(arrowsize) + ')" freecad:skip="1" '
svg += 'fill="' + color + '" stroke="none" '
svg += 'style="stroke-miterlimit:4;stroke-dasharray:none" '
svg += 'd="M 0 0 L 4 1 L 4 -1 Z"/>\n'
elif arrowtype == 'Tick':
svg += '<path transform="rotate(' + str(math.degrees(angle))
svg += ',' + str(point.x) + ',' + str(point.y) + ') '
svg += 'translate(' + str(point.x) + ',' + str(point.y) + ') '
svg += 'scale(' + str(arrowsize) + ',' + str(arrowsize) + ')" freecad:skip="1" '
svg += 'fill="' + color + '" stroke="none" '
svg += 'style="stroke-miterlimit:4;stroke-dasharray:none" '
svg += 'd="M -1 -2 L 0 2 L 1 2 L 0 -2 Z"/>\n'
elif arrowtype == 'Tick-2':
svg += '<line transform="rotate(' + str(math.degrees(angle) + 45)
svg += ',' + str(point.x) + ',' + str(point.y) + ') '
svg += 'translate(' + str(point.x) + ',' + str(point.y) + ') '
svg += '" freecad:skip="1" '
svg += 'fill="none" stroke="' + color + '" '
svg += 'style="stroke-dasharray:none;stroke-linecap:square;'
svg += 'stroke-width:' + str(linewidth) + '" '
svg += 'x1="-' + str(arrowsize*2) + '" y1="0" '
svg += 'x2="' + str(arrowsize*2) + '" y2="0" />\n'
else:
print("getSVG: arrow type not implemented")
return svg
def get_overshoot(point, shootsize, color, linewidth, angle=0):
svg = '<line transform="rotate(' + str(math.degrees(angle))
svg += ',' + str(point.x) + ',' + str(point.y) + ') '
svg += 'translate(' + str(point.x) + ',' + str(point.y) + ') '
svg += '" freecad:skip="1" '
svg += 'fill="none" stroke="' + color + '" '
svg += 'style="stroke-dasharray:none;stroke-linecap:square;'
svg += 'stroke-width:' + str(linewidth) + '" '
svg += 'x1="0" y1="0" '
svg += 'x2="' + str(shootsize*-1) + '" y2="0" />\n'
return svg
def get_text(color, fontsize, fontname, angle, base, text, linespacing=0.5, align="center", flip=True):
if isinstance(angle, FreeCAD.Rotation):
if not plane:
angle = angle.Angle
else:
if plane.axis.getAngle(angle.Axis) < 0.001:
angle = angle.Angle
elif abs(plane.axis.getAngle(angle.Axis) - math.pi) < 0.001:
return '' # text is perpendicular to view, so it shouldn't appear
else:
angle = 0 # TODO maybe there is something better to do here?
if not isinstance(text, list):
text = text.split('\n')
if align.lower() == 'center':
anchor = 'middle'
elif align.lower() == 'left':
anchor = 'start'
else:
anchor = 'end'
if techdraw:
svg = ""
for i in range(len(text)):
t = text[i]
#if not isinstance(t,unicode):
# t = t.decode("utf8")
# possible workaround if UTF8 is unsupported
# import unicodedata
# t = u"".join([c for c in unicodedata.normalize("NFKD",t) if not unicodedata.combining(c)]).encode("utf8")
svg += '<text fill="' + color +'" font-size="' + str(fontsize) + '" '
svg += 'style="text-anchor:' + anchor + ';text-align:' + align.lower() + ';'
svg += 'font-family:' + fontname + '" '
svg += 'transform="rotate(' + str(math.degrees(angle))
svg += ',' + str(base.x) + ',' + str(base.y - linespacing * i) + ') '
svg += 'translate(' + str(base.x) + ',' + str(base.y - linespacing * i) + ') '
svg += 'scale(1,-1)" '
#svg += '" freecad:skip="1"'
svg += '>\n' + t + '</text>\n'
else:
svg = '<text fill="'
svg += color + '" font-size="'
svg += str(fontsize) + '" '
svg += 'style="text-anchor:' + anchor + ';text-align:' + align.lower() + ';'
svg += 'font-family:' + fontname + '" '
svg += 'transform="rotate(' + str(math.degrees(angle))
svg += ','+ str(base.x) + ',' + str(base.y) + ') '
if flip:
svg += 'translate(' + str(base.x) + ',' + str(base.y) + ')'
else:
svg += 'translate(' + str(base.x) + ',' + str(-base.y) + ')'
# svg += 'scale('+str(tmod/2000)+',-'+str(tmod/2000)+') '
if flip:
svg += ' scale(1,-1) '
else:
svg += ' scale(1,1) '
svg += '" freecad:skip="1"'
svg += '>\n'
if len(text) == 1:
try:
svg += text[0]
except:
svg += text[0].decode('utf8')
else:
for i in range(len(text)):
if i == 0:
svg += '<tspan>'
else:
svg += '<tspan x="0" dy="' + str(linespacing) + '">'
try:
svg += text[i]
except:
svg += text[i].decode('utf8')
svg += '</tspan>\n'
svg += '</text>\n'
return svg
# calculate the 4 points
p1 = obj.Start
p4 = obj.End
base = None
if hasattr(obj, 'Direction'):
if not DraftVecUtils.isNull(obj.Direction):
v2 = p1.sub(obj.Dimline)
v3 = p4.sub(obj.Dimline)
v2 = DraftVecUtils.project(v2, obj.Direction)
v3 = DraftVecUtils.project(v3, obj.Direction)
p2 = obj.Dimline.add(v2)
p3 = obj.Dimline.add(v3)
if DraftVecUtils.equals(p2, p3):
base = None
proj = None
else:
base = Part.LineSegment(p2, p3).toShape()
proj = DraftGeomUtils.findDistance(p1, base)
if proj:
proj = proj.negative()
if not base:
if DraftVecUtils.equals(p1, p4):
base = None
proj = None
else:
base = Part.LineSegment(p1, p4).toShape()
proj = DraftGeomUtils.findDistance(obj.Dimline, base)
if proj:
p2 = p1.add(proj.negative())
p3 = p4.add(proj.negative())
else:
p2 = p1
p3 = p4
if proj:
# if hasattr(obj.ViewObject,"ExtLines"):
extlines = 0
DisplayMode = '2D'
dmax = extlines
if dmax and (proj.Length > dmax):
if (dmax > 0):
p1 = p2.add(DraftVecUtils.scaleTo(proj, dmax))
p4 = p3.add(DraftVecUtils.scaleTo(proj, dmax))
else:
rest = proj.Length + dmax
p1 = p2.add(DraftVecUtils.scaleTo(proj, rest))
p4 = p3.add(DraftVecUtils.scaleTo(proj, rest))
else:
proj = p3.sub(p2).cross(FreeCAD.Vector(0, 0, 1))
if getType(obj) == 'Dimension':
fontsize = 60
ts = (len(str(obj.Distance)) * fontsize) / 4.0
rm = ((p3.sub(p2)).Length / 2.0) - ts
p2a = get_proj(p2.add(DraftVecUtils.scaleTo(p3.sub(p2), rm)))
p2b = get_proj(p3.add(DraftVecUtils.scaleTo(p2.sub(p3), rm)))
p1 = get_proj(p1)
p2 = get_proj(p2)
p3 = get_proj(p3)
p4 = get_proj(p4)
# calculate the text position and orientation
if hasattr(obj, 'Normal'):
if DraftVecUtils.isNull(obj.Normal):
if proj:
norm = (p3.sub(p2).cross(proj)).negative()
else:
norm = Vector(0, 0, 1)
else:
norm = FreeCAD.Vector(obj.Normal)
else:
if proj:
norm = (p3.sub(p2).cross(proj)).negative()
else:
norm = Vector(0, 0, 1)
if not DraftVecUtils.isNull(norm):
norm.normalize()
u = p3.sub(p2)
u.normalize()
v1 = norm.cross(u)
rot1 = FreeCAD.Placement(DraftVecUtils.getPlaneRotation(u, v1, norm)).Rotation.Q
FLIPARROWS = True
if FLIPARROWS:
u = u.negative()
v2 = norm.cross(u)
rot2 = FreeCAD.Placement(DraftVecUtils.getPlaneRotation(u, v2, norm)).Rotation.Q
if p1 != p2:
u3 = p1.sub(p2)
u3.normalize()
v3 = norm.cross(u3)
rot3 = FreeCAD.Placement(DraftVecUtils.getPlaneRotation(u3, v3, norm)).Rotation.Q
TEXTSPACING=60
if TEXTSPACING:
offset = DraftVecUtils.scaleTo(v1, TEXTSPACING)
else:
offset = DraftVecUtils.scaleTo(v1, 0.05)
rott = rot1
FLIPTEXT = True
if FLIPTEXT:
rott = FreeCAD.Rotation(*rott).multiply(FreeCAD.Rotation(norm, 180)).Q
offset = offset.negative()
tbase = (p2.add((p3.sub(p2).multiply(0.5)))).add(offset)
angle = - DraftVecUtils.angle(p3.sub(p2))
# drawing lines
svg = '<path '
if DisplayMode == '2D':
tangle = angle
if tangle > math.pi / 2:
tangle = tangle - math.pi
if rotation != 0:
if abs(tangle + math.radians(rotation)) < 0.0001:
tangle += math.pi
tbase = tbase.add(DraftVecUtils.rotate(FreeCAD.Vector(0, 2 / scale, 0), tangle))
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.add(FreeCAD.Vector(0, -2.0 / scale, 0))
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) + '" '
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" '
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(obj.ViewObject,"DimOvershoot") and obj.ViewObject.DimOvershoot.Value:
# shootsize = obj.ViewObject.DimOvershoot.Value/pointratio
# svg += get_overshoot(p2,shootsize,stroke,linewidth,angle)
# svg += get_overshoot(p3,shootsize,stroke,linewidth,angle+math.pi)
# if hasattr(obj.ViewObject,"ExtOvershoot") and obj.ViewObject.ExtOvershoot.Value:
# shootsize = obj.ViewObject.ExtOvershoot.Value/pointratio
# shootangle = -DraftVecUtils.angle(p1.sub(p2))
# svg += get_overshoot(p2,shootsize,stroke,linewidth,shootangle)
# svg += get_overshoot(p3,shootsize,stroke,linewidth,shootangle)
#
# # drawing arrows
#if hasattr(obj.ViewObject,"ArrowType"):
FlipArrows = False
ArrowSize = 10
ArrowType = 'Arrow'
arrowsize = ArrowSize / pointratio
if FlipArrows:
angle = angle + math.pi
svg += get_arrow(ArrowType, p2, arrowsize, stroke, linewidth, angle)
svg += get_arrow(ArrowType, p3, arrowsize, stroke, linewidth, angle + math.pi)
# drawing text
# mid_point = FreeCAD.Vector((p2.x + p3.x) / 2, (p2.y + p3.y) / 2,(p2.z + p3.z) / 2)
# mid_point = mid_point.add(offset)
FontName = ''
total_length = (obj.Start.sub(obj.End)).Length
obj.Distance = total_length
svg += get_text(stroke, fontsize, FontName, tangle, tbase, str(obj.Distance))
# techdraw expects bottom-to-top coordinates
if techdraw:
svg = '<g transform ="scale(1,-1)">' + svg + '</g>'
return svg
import FreeCAD
from dimensions import create_boundary_dimensions
from export_svg import export_svg
def main():
svg_file_path = './resultant_svg.svg'
document_name = 'export_dimensions'
FreeCAD.newDocument(document_name)
FreeCAD.setActiveDocument(document_name)
FreeCAD.ActiveDocument = FreeCAD.getDocument(document_name)
box = FreeCAD.ActiveDocument.addObject("Part::Box","Box")
box.Length = 500
box.Width = 500
box.Height = 400
FreeCAD.ActiveDocument.recompute()
dims = create_boundary_dimensions(box)
export_svg([box], dims=dims, file_path=svg_file_path)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment