Hello, here some example, maybe too verbose, but it works and show probably the point:
Code: Select all
"""TechDraw Example.
file: 20230612-TechDraw_example.py
Copyright 2023 Carlo Dormeletti
THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
"""
import importlib # noqa
import math # noqa
import os # noqa
import sys # noqa
from datetime import datetime
from math import asin, atan, cos, degrees, pi, radians, sin, sqrt # noqa
import FreeCAD # noqa
import FreeCADGui # noqa
import Part
#from ProfileLib import RegularPolygon
import Sketcher
# needed only if you want to do Techdraw page export
import TechDrawGui # noqa
from FreeCAD import Placement, Rotation # noqa
import PySide
from PySide import QtGui, QtCore
ver_nm = "1.0c"
today = datetime.today().strftime('%Y%m%d')
# USER MODIFIABLE
DOC_Name = f"TD_example{today}"
# Path management
MODULE_PATH = os.path.dirname(__file__)
HOME_DIR = os.path.expanduser('~')
RES_DIR = FreeCAD.getResourceDir()
DBG_LOAD = False
if MODULE_PATH not in sys.path:
if DBG_LOAD is True:
print("no module path")
sys.path.insert(-1, MODULE_PATH)
else:
if DBG_LOAD is True:
print("module path is present")
# Assign shortest objects name
V3d = FreeCAD.Vector
V2d = FreeCAD.Base.Vector2d
# START Shortcuts
EPS = 0.01
EPS_C = EPS * -0.5
VEC0 = V3d(0, 0, 0)
ROT0 = Rotation(0, 0, 0)
DVZ = V3d(0, 0, 1)
DVX = V3d(1, 0, 0)
DVY = V3d(0, 1, 0)
# END Shortcuts
# SERVICE METHODS
def clear_doc(doc_name):
"""Clear the document deleting all the objects."""
doc = FreeCAD.getDocument(doc_name)
try:
while len(doc.Objects) > 0:
doc.removeObject(doc.Objects[0].Name)
except Exception as e:
print(f'Exception: {e}')
def ensure_document(doc_name, action=0):
"""Ensure existence of document with doc_name and clear the doc."""
doc_root = FreeCAD.listDocuments()
doc_exist = False
for d_name, doc in doc_root.items():
# debug info do not delete
print(f"ED: doc name = {d_name}")
if d_name == doc_name:
print("Match name")
if action == 1:
# when using clear_doc() is not possible like in Part.Design
FreeCAD.closeDocument(doc_name)
doc_exist = False
elif action == 2:
doc_exist = True
clear_doc(doc_name)
FreeCAD.setActiveDocument(d_name)
else:
doc_exist = True
FreeCAD.setActiveDocument(d_name)
if doc_exist is False:
# debug info do not delete
# print("ED: Create = {}".format(doc_name))
FreeCAD.newDocument(doc_name)
return FreeCAD.activeDocument().Name
def setview(doc_name, t_v=0):
"""Set viewport in 3D view."""
FreeCAD.setActiveDocument("")
FreeCAD.ActiveDocument = None
FreeCADGui.ActiveDocument = None
FreeCAD.setActiveDocument(doc_name)
FreeCADGui.ActiveDocument = FreeCADGui.getDocument(doc_name)
VIEW = FreeCADGui.ActiveDocument.ActiveView
if t_v == 0:
VIEW.viewTop()
elif t_v == 1:
VIEW.viewFront()
else:
VIEW.viewAxometric()
VIEW.setAxisCross(True)
VIEW.fitAll()
# Building methods
def circle_tangent(rad, ccen, p0):
"""Determine tangent points on a circle."""
dx = p0.x - ccen.x
dy = p0.y - ccen.y
dxr, dyr = -dy, dx
d = sqrt(dx**2 + dy**2)
if d >= rad :
rho = rad / d
ad = rho**2
bd = rho * sqrt(1 - rho**2)
x1 = ccen.x + ad * dx + bd * dxr
y1 = ccen.y + ad * dy + bd * dyr
x2 = ccen.x + ad * dx - bd * dxr
y2 = ccen.y + ad * dy - bd * dyr
tp1 = V3d(x1, y1, 0)
tp2 = V3d(x2, y2, 0)
return tp1, tp2
# Assembly and PD modules
def get_body_plane(body, p_name="XY_Plane"):
"""Return the proper Object name for a plane."""
for feat in body.Origin.OriginFeatures:
if p_name in feat.Name:
return feat
else:
None
def create_pd_body(doc, body_nm, lcs=False):
"""Create new Part Design Body."""
newBody = doc.addObject("PartDesign::Body", body_nm)
if lcs is True:
# add an LCS at the root of the Part, and attach it to the 'Origin'
lcs0 = newBody.newObject('PartDesign::CoordinateSystem', f'{body_nm}_lc0')
lcs0.Support = [(newBody.Origin.OriginFeatures[0], '')]
lcs0.MapMode = 'ObjectXY'
lcs0.MapReversed = False
newBody.recompute()
doc.recompute()
return newBody
def sketch_polyline(vertexList, closed=True, addHVConstraints=True):
"""Skecth a polyline."""
geoList = []
conList = []
npts = len(vertexList)
for i in range(npts - 1):
geoList.append(Part.LineSegment(vertexList[i], vertexList[i + 1]))
if closed:
geoList.append(Part.LineSegment(vertexList[-1], vertexList[0]))
for i in range(npts - 1):
conList.append(Sketcher.Constraint('Coincident', i, 2, i + 1, 1))
if closed:
conList.append(Sketcher.Constraint('Coincident', npts - 1, 2, 0, 1))
if addHVConstraints:
for i, ls in enumerate(geoList):
if abs(ls.tangent(0)[0].y) < 1e-14:
conList.append(Sketcher.Constraint('Horizontal', i))
elif abs(ls.tangent(0)[0].x) < 1e-14:
conList.append(Sketcher.Constraint('Vertical', i))
return (geoList, conList)
def sketch_rrect(sk, wid, lgt, c_rad, cent="bl", css=()):
"""Sketch a rounded rectangle.
Inspired from FreeCAD echoed code.
"""
xc1 = wid - c_rad
yc1 = lgt - c_rad
ac1 = sk.addGeometry(Part.ArcOfCircle(
Part.Circle(V3d(c_rad, c_rad, 0), DVZ, c_rad), -pi, pi * -0.5))
ln1 = sk.addGeometry(Part.LineSegment(V3d(0.0, c_rad, 0), V3d(0.0, yc1, 0)))
ac2 = sk.addGeometry(Part.ArcOfCircle(
Part.Circle(V3d(c_rad, yc1, 0), DVZ, c_rad), pi * -1.5, -pi))
ln2 = sk.addGeometry(Part.LineSegment(V3d(c_rad, lgt, 0), V3d(xc1, lgt, 0)))
ac3 = sk.addGeometry(Part.ArcOfCircle(
Part.Circle(V3d(xc1, yc1, 0), DVZ, c_rad), pi * -2.0, pi * -1.5))
ln3 = sk.addGeometry(Part.LineSegment(V3d(wid, yc1, 0), V3d(wid, c_rad, 0)))
ac4 = sk.addGeometry(Part.ArcOfCircle(
Part.Circle(V3d(xc1, c_rad, 0), DVZ, c_rad), pi * -2.5, pi * - 2.0))
ln4 = sk.addGeometry(Part.LineSegment(V3d(xc1, 0.0, 0), V3d(c_rad, 0.0, 0)))
# print(ac1, ac2, ac3, ac4)
# print(ln1, ln2, ln3, ln4)
conList = []
conList.append(Sketcher.Constraint('Tangent', ac1, 1, ln1, 1))
conList.append(Sketcher.Constraint('Tangent', ln1, 2, ac2, 2))
conList.append(Sketcher.Constraint('Tangent', ac2, 1, ln2, 1))
conList.append(Sketcher.Constraint('Tangent', ln2, 2, ac3, 2))
conList.append(Sketcher.Constraint('Tangent', ac3, 1, ln3, 1))
conList.append(Sketcher.Constraint('Tangent', ln3, 2, ac4, 2))
conList.append(Sketcher.Constraint('Tangent', ac4, 1, ln4, 1))
conList.append(Sketcher.Constraint('Tangent', ln4, 2, ac1, 2))
conList.append(Sketcher.Constraint('Horizontal', ln2))
conList.append(Sketcher.Constraint('Horizontal', ln4))
conList.append(Sketcher.Constraint('Vertical', ln1))
conList.append(Sketcher.Constraint('Vertical', ln3))
sk.addConstraint(conList)
del conList
c_r1 = sk.addConstraint(Sketcher.Constraint('Radius', ac1, c_rad))
cc_lst = [c_r1]
if cent == 'cc':
pass
else:
c_r2 = sk.addConstraint(Sketcher.Constraint('Radius', ac2, c_rad))
cc_lst.append(c_r2)
c_r3 = sk.addConstraint(Sketcher.Constraint('Radius', ac3, c_rad))
cc_lst.append(c_r3)
c_wid = sk.addConstraint(Sketcher.Constraint('DistanceX', ac1, 1, ln3, 2, wid))
c_len = sk.addConstraint(Sketcher.Constraint('DistanceY', ac1, 2, ac2, 1, lgt))
if css == ():
pass
else:
sk.setExpression(f'Constraints[{c_wid}]', css[0])
sk.setExpression(f'Constraints[{c_len}]', css[1])
for c_num in cc_lst:
sk.setExpression(f'Constraints[{c_num}]', css[2])
blc = sk.addGeometry(Part.Point(V3d(0.0, 0.0, 0)), True)
trc = sk.addGeometry(Part.Point(V3d(wid, lgt, 0)), True)
conList = []
conList.append(Sketcher.Constraint('PointOnObject', blc, 1, ln1))
conList.append(Sketcher.Constraint('PointOnObject', blc, 1, ln4))
conList.append(Sketcher.Constraint('PointOnObject', trc, 1, ln2))
conList.append(Sketcher.Constraint('PointOnObject', trc, 1, ln3))
sk.addConstraint(conList)
del conList
if cent == 'cc':
sk.addConstraint(Sketcher.Constraint('Symmetric', ac1, 2, ac2, 1, -1))
sk.addConstraint(Sketcher.Constraint('Symmetric', ac1, 1, ln3, 2, -2))
elif cent == 'bl':
sk.addConstraint(Sketcher.Constraint('Coincident', blc, 1, -1, 1))
elif cent == 'cw':
sk.addConstraint(Sketcher.Constraint('PointOnObject',1, 2, -2))
sk.addConstraint(Sketcher.Constraint('Symmetric', 6, 1, 3, 2, -1))
elif cent == 'cl':
pass
sk.recompute()
return sk
def sketch_wire(sk, wire):
"""Create a correctly closed sketch from a list of edges.
Portion of code courtesy of Roy_043
"""
#
geoList = []
for w_edge in wire:
pm1 = w_edge.ParameterRange[0]
pm2 = w_edge.ParameterRange[1]
e_curve = w_edge.Curve
if hasattr(e_curve, "Axis") and vec_is_same(e_curve.Axis, V3d(0, 0, -1)):
e_curve.reverse()
pm1, pm2 = -pm2, pm1
geoList.append(e_curve.trim(pm1, pm2))
sk.addGeometry(geoList, False)
conListEnds = []
conListOther = []
segPts = [(g.StartPoint, g.EndPoint) for g in geoList]
segTans = [(g.tangent(g.FirstParameter)[0], g.tangent(g.LastParameter)[0]) for g in geoList]
segs = list(range(len(geoList))) # List of indices.
nxts = segs[1:] + [segs[0]] # List of next indices.
for seg, nxt in zip(segs, nxts):
segGeo = geoList[seg]
nxtGeo = geoList[nxt]
segPtSta, segPtEnd = segPts[seg]
nxtPtSta, nxtPtEnd = segPts[nxt]
segTanSta, segTanEnd = segTans[seg]
nxtTanSta, nxtTanEnd = segTans[nxt]
conTyp = ""
if vec_is_same(segPtEnd, nxtPtSta):
conTyp = "Tangent" if tan_is_same(segTanEnd, nxtTanSta) else "Coincident"
conListEnds.append(Sketcher.Constraint(conTyp, seg, 2, nxt, 1))
elif vec_is_same(segPtEnd, nxtPtEnd):
conTyp = "Tangent" if tan_is_same(segTanEnd, nxtTanEnd) else "Coincident"
conListEnds.append(Sketcher.Constraint(conTyp, seg, 2, nxt, 2))
elif vec_is_same(segPtSta, nxtPtSta):
conTyp = "Tangent" if tan_is_same(segTanSta, nxtTanSta) else "Coincident"
conListEnds.append(Sketcher.Constraint(conTyp, seg, 1, nxt, 1))
elif vec_is_same(segPtSta, nxtPtEnd):
conTyp = "Tangent" if tan_is_same(segTanSta, nxtTanEnd) else "Coincident"
conListEnds.append(Sketcher.Constraint(conTyp, seg, 1, nxt, 2))
if segGeo.TypeId == "Part::GeomLineSegment":
# Avoid redundant Horizontal/Vertical constraint if the next
# connected line is parallel:
if conTyp == "Tangent" and nxtGeo.TypeId == "Part::GeomLineSegment":
pass
elif tan_is_same(segTanSta, V3d(1, 0, 0)):
conListOther.append(Sketcher.Constraint("Horizontal", seg))
elif tan_is_same(segTanSta, V3d(0, 1, 0)):
conListOther.append(Sketcher.Constraint("Vertical", seg))
elif segGeo.TypeId == "Part::GeomArcOfCircle":
rad = segGeo.Radius
conListOther.append(Sketcher.Constraint('Radius', seg, rad))
sk.addConstraint(conListEnds)
sk.addConstraint(conListOther)
return sk
def tan_is_same(tanA, tanB):
"""Check if two tan are same, with some tolerances."""
return tanA.isEqual(tanB, 1e-8) or tanA.isEqual(-tanB, 1e-8)
def vec_is_same(vecA, vecB):
"""Check if two vectors are equal, with some tolerance."""
return vecA.isEqual(vecB, 1e-8)
# BUILDING CODE START HERE
# SPREADHEETS METHODS
def ss_color(d_sheet, cells, color):
"""Set cell color."""
for c_ref in cells:
d_sheet.setBackground(c_ref, color[0])
d_sheet.setForeground(c_ref, color[1])
def init_doc_ss(d_doc, dbg_p=False):
"""Set spreadsheet headers."""
#
c_sheet = d_doc.addObject("Spreadsheet::Sheet", "ModelData")
ss_head = (
('A1', 'Model'), ('D1', "Generic Data"),
)
ss_desc = (
# Generic Data
('D2', 'GenRad'), ('D3', 'GenDepth'),
('A3', 'Radius 2'),
('A4', 'Height 1'), ('A5', 'Base Lenght'), ('A6', 'Base Width'),
('A7', 'Base Thickness'), ('A8', 'Displacement X'),
('A9', 'Bracket WaB'), ('A10', 'Bracket Top Rad'),
('A11', 'Bracket Height'), ('A12', 'Bracket Thickness'),
)
# ss_data format (cell, value, alias)
ss_data = [
# Generic
('E2', '5.0mm', 'gen_rad'),
('E3', '10.0mm', 'gen_dep'),
('B3', '89.0mm', 'mdm_r2'),
('B4', '19.0mm', 'mdm_h1'),
('B5', '110.0mm', 'mdm_blen'),
('B6', '130.0mm', 'mdm_bwid'),
('B7', '50.0mm', 'mdm_bthi'),
('B8', '45.0mm', 'mdm_bdpx'),
('B9', '100mm', 'md_bk_bw'),
('B10', '22.0mm', 'md_bk_tpr'),
('B11', '114.0mm', 'md_bk_hei'),
('B12', '25.0mm', 'md_bk_thi'),
]
for head in ss_head:
c_sheet.set(head[0], head[1])
for desc in ss_desc:
c_sheet.set(desc[0], desc[1])
# Apply Color to Header Cells
hd_cells = (v[0] for v in ss_head)
hd_colors = ((0.0, 1.0, 1.0), (0.0, 0.0, 0.0))
ss_color(c_sheet, hd_cells, hd_colors)
# Apply Color to Descriptions Cells
desc_cells = (v[0] for v in ss_desc)
ds_colors = ((0.5, 1.0, 0.75), (0.0, 0.0, 0.0))
ss_color(c_sheet, desc_cells, ds_colors)
# Populate cells with data
for data in ss_data:
c_sheet.set(data[0], data[1])
if len(data) > 2:
c_sheet.setAlias(data[0], data[2])
c_sheet.recompute()
return c_sheet
# ANNOTATION SYSTEM
def createTD(d_doc, td_pnm):
"""Create a TechDraw page."""
tmplSpec = 'Mod/TechDraw/Templates/A4_Landscape_blank.svg'
tmpl_file = os.path.join(RES_DIR, tmplSpec)
page = d_doc.addObject('TechDraw::DrawPage', td_pnm)
template = d_doc.addObject('TechDraw::DrawSVGTemplate', f'{td_pnm}_tmpl')
template.Template = tmpl_file
page.Template = d_doc.getObject(template.Name)
texts = page.Template.EditableTexts
#for key, value in texts.items():
# print("{0} = {1}".format(key, value))
page.recompute()
d_doc.recompute()
def TD_addView(d_doc, view_nm, td_pnm, obj, vdir, dscale):
"""Add a TD View to a page."""
view = d_doc.addObject('TechDraw::DrawViewPart', view_nm)
page = d_doc.getObject(td_pnm)
page.addView(view)
view.Direction = vdir
#view.XDirection = vdir
view.ScaleType = u"Custom"
view.Scale = dscale
view.Source = obj
view.recompute()
page.recompute()
d_doc.recompute()
return view
def TDaddMlab(d_doc, page, mlab, mtyp, mref2d, mnote, mpos, show_dim=False):
"""Add a measure to a page."""
dim = d_doc.addObject('TechDraw::DrawViewDimension')
dim.Label = mlab
dim.Type = mtyp
dim.References2D = mref2d
if show_dim is False:
dim.FormatSpec = mnote
dim.Arbitrary = True
dim.X = mpos[0]
dim.Y = mpos[1]
dim.recompute()
page.addView(dim)
# BUILDING METHODS
def main_body(d_doc, bd_nm, c_sheet, note=0):
"""Make main body."""
# get some data from spreadsheet
mdm_bl = c_sheet.get('mdm_blen').Value
mdm_bw = c_sheet.get('mdm_bwid').Value
md_bk_th = c_sheet.get('md_bk_thi').Value
body = create_pd_body(d_doc, bd_nm)
sk = body.newObject('Sketcher::SketchObject')
sk.Label = f'{bd_nm}_base'
sk.MapMode = 'FlatFace'
sk.Support = (get_body_plane(body, 'XY_Plane'), [''])
sk.addGeometry(Part.Circle(VEC0, DVZ, 10), False)
rc_1 = sk.addConstraint(
Sketcher.Constraint('Radius', 0, 10))
sk.setExpression(f'Constraints[{rc_1}]', u'<<ModelData>>.mdm_r2')
sk.addConstraint(Sketcher.Constraint('Coincident', 0, 3, -1, 1))
sk.Visibility = False
# First pad
pa1 = body.newObject('PartDesign::Pad')
pa1.Label = f'{bd_nm}_pad'
pa1.Profile = sk
pa1.Reversed = False
pa1.Midplane = False
pa1.Type = u"Length"
pa1.setExpression('Length', u'<<ModelData>>.mdm_h1')
pa1.UseCustomVector = False
pa1.Direction = (0, 0, 1)
pa1.ReferenceAxis = (sk, ['N_Axis'])
pa1.AlongSketchNormal = 1
pa1.UpToFace = None
pa1.TaperAngle = 0.0
pa1.Offset = 0.0
pa1.recompute()
sk.recompute()
# Base block
sk1 = body.newObject('Sketcher::SketchObject')
sk1.Label = f'{bd_nm}_BB_sk1'
sk1.MapMode = 'FlatFace'
sk1.Support = (get_body_plane(body, 'XY_Plane'), [''])
geoList, conList = sketch_polyline(
[VEC0, V3d(mdm_bl, 0, 0),
V3d(mdm_bl, mdm_bw, 0),
V3d(0, mdm_bw, 0)])
(line0, line1, line2, line3) = sk1.addGeometry(geoList, False)
sk1.addConstraint(conList)
sk1.addConstraint(Sketcher.Constraint('Symmetric', line0, 2, line1, 2, -1))
# delete the automatically added vertical constraint
sk1.delConstraint(5)
bs_dx = sk1.addConstraint(Sketcher.Constraint('DistanceX', -1, 1, line0, 1, -2.0))
sk1.setExpression(
f'Constraints[{bs_dx}]',
'<<ModelData>>.mdm_r2 * -1 + <<ModelData>>.mdm_bdpx')
ywc = sk1.addConstraint(
Sketcher.Constraint('DistanceX', line0, 1, line1, 2, mdm_bl))
sk1.setExpression(f'Constraints[{ywc}]', '<<ModelData>>.mdm_blen')
sk1.renameConstraint(ywc, u'ywid')
xlc = sk1.addConstraint(
Sketcher.Constraint('DistanceY', line3, 2, line3, 1, mdm_bw))
sk1.setExpression(f'Constraints[{xlc}]', '<<ModelData>>.mdm_bwid')
sk1.renameConstraint(xlc, u'xlen')
sk1.setExpression('.AttachmentOffset.Base.z', f'{pa1.Name}.Length')
sk1.recompute()
sk1.Visibility = False
# Base pad
pa2 = body.newObject('PartDesign::Pad')
pa2.Label = f'{bd_nm}_BB_pad'
pa2.Profile = sk1
pa2.Reversed = False
pa2.Midplane = False
pa2.Type = u"Length"
pa2.setExpression('Length', u'<<ModelData>>.mdm_bthi')
pa2.UseCustomVector = False
pa2.Direction = (0, 0, 1)
pa2.ReferenceAxis = (sk1, ['N_Axis'])
pa2.AlongSketchNormal = True
pa2.UpToFace = None
pa2.TaperAngle = 0.0
pa2.Offset = 0.0
pa2.recompute()
body.Tip = pa2
# Bracket
sk2 = body.newObject('Sketcher::SketchObject')
sk2.Label = f'{bd_nm}_BKT_sk'
sk2.MapMode = 'FlatFace'
sk2.Support = (get_body_plane(body, 'XZ_Plane'), [''])
sketch_wire(sk2, md_bck(c_sheet))
bll = sk2.addConstraint(Sketcher.Constraint('DistanceX', 3, 1, 3, 2, 15.0))
sk2.setExpression(f'Constraints[{bll}]', u'<<ModelData>>.md_bk_bw')
sk2.renameConstraint(bll, 'bl_len')
bkh = sk2.addConstraint(Sketcher.Constraint('DistanceY', 0, 1, 1, 3, 10))
sk2.setExpression(f'Constraints[{bkh}]', u'<<ModelData>>.md_bk_hei')
# Equal constraint two slanted lines
sk2.addConstraint(Sketcher.Constraint('Equal', 2, 0))
# middle point of line1
mpbl = sk2.addGeometry(Part.Point(VEC0))
sk2.addConstraint(Sketcher.Constraint('PointOnObject', mpbl, 1, 3))
mpbl_c = sk2.addConstraint(Sketcher.Constraint('DistanceX', 3, 1, mpbl, 1, 10))
sk2.setExpression(f'Constraints[{mpbl_c}]', '.Constraints.bl_len * 0.5')
# pivot hole
pv_ho = sk2.addGeometry(Part.Circle(VEC0, DVZ, 1.0))
sk2.addConstraint(Sketcher.Constraint('Coincident', pv_ho, 3, 1, 3))
phr = sk2.addConstraint(Sketcher.Constraint('Radius', pv_ho, 5.0))
sk2.setExpression(f'Constraints[{phr}]', u'<<ModelData>>.gen_rad')
# external reference to position sketch on top of base block
sk2.addExternal(f'{sk1.Name}',"Edge3") # id -3
sk2.addConstraint(Sketcher.Constraint('Symmetric', -3, 1, -3, 2, mpbl, 1))
sk2.Visibility = False
sk2.recompute()
ssb1 = body.newObject('PartDesign::SubShapeBinder')
ssb1.Label = f'{bd_nm}_BKT_bind1'
ssb1.Support = sk2
ssb1.setExpression('.Placement.Base.z', f'{pa2.Name}.Length')
ssb1.setExpression('.Placement.Base.y', f'{sk1.Name}.Constraints.xlen * -0.5')
ssb1.Visibility = False
ssb1.recompute()
# Pad to proper thickness
pa3 = body.newObject('PartDesign::Pad')
pa3.Label = f'{bd_nm}_BKT_r'
pa3.Profile = ssb1
pa3.Reversed = False
pa3.Midplane = False
pa3.Type = u"Length"
pa3.setExpression('Length', u'<<ModelData>>.md_bk_thi')
pa3.UseCustomVector = False
pa3.Direction = (0, 0, 1)
pa3.ReferenceAxis = None
pa3.AlongSketchNormal = True
pa3.UpToFace = None
pa3.TaperAngle = 0.0
pa3.Offset = 0.0
pa3.recompute()
body.Tip = pa3
ssb2 = body.newObject('PartDesign::SubShapeBinder')
ssb2.Label = f'{bd_nm}_BKT_bind2'
ssb2.Support = sk2
ssb2.setExpression('.Placement.Base.z', f'{pa2.Name}.Length')
ssb2.setExpression('.Placement.Base.y', f'{sk1.Name}.Constraints.xlen * 0.5')
ssb2.Visibility = False
ssb2.recompute()
pa4 = body.newObject('PartDesign::Pad')
pa4.Label = f'{bd_nm}_BKT_l'
pa4.Profile = ssb2
pa4.Reversed = True
pa4.Midplane = False
pa4.Type = u"Length"
pa4.setExpression('Length', u'<<ModelData>>.md_bk_thi')
pa4.UseCustomVector = False
pa4.Direction = (0, 0, 1)
pa4.ReferenceAxis = None
pa4.AlongSketchNormal = True
pa4.UpToFace = None
pa4.TaperAngle = 0.0
pa4.Offset = 0.0
pa4.recompute()
body.Tip = pa4
body.recompute()
# Create TechDraw View
# Note: we could be bitten by TNP so reference have to be checked
# if geometry change
if note > 0:
page_nm = f'{bd_nm}_Page'
createTD(dest_doc, page_nm)
page = d_doc.getObject(page_nm)
view = TD_addView(d_doc, f'{bd_nm}_View', page_nm, body, V3d(0,1,0), 0.50)
TDaddMlab(
d_doc, page, "dim1", "DistanceX", [(view, 'Edge8')],
"Bracket WaB", (-14.0, +6.0))
TDaddMlab(
d_doc, page, "dim2", "DistanceX",
[(view, 'Vertex6'), (view, 'Vertex8')],
"Base width", (-13.0, -27.0))
TDaddMlab(
d_doc, page, "dim3", "DistanceY",
[(view, 'Vertex1'), (view, 'Vertex4')],
"Height 1", (+64.0, -26.0))
TDaddMlab(
d_doc, page, "dim4", "DistanceX",
[(view, 'Vertex0'), (view, 'Vertex1')],
"Radius 2", (0.0, -61.0))
TDaddMlab(
d_doc, page, "dim6", "Radius",
[(view, 'Edge13')],
"Hole Radius", (+19.0, +42.0))
TDaddMlab(
d_doc, page, "dim6", "Radius",
[(view, 'Edge11')],
"Bracket Top Radius", (-54.0, +61.0))
edg = view.getEdgeBySelection("Edge13")
edg_cen = edg.Curve.Center
cvtx = view.makeCosmeticVertex(edg_cen)
vtx_id = view.getCosmeticVertex(cvtx)
TDaddMlab(
d_doc, page, "dim5", "DistanceY",
[(view, 'Vertex15'), (view, 'Edge8')],
#[vtx_id, (view, 'Edge8')],
"Bracket Height", (-57.0, 16.0))
view.X = 84
view.Y = 138
view.recompute()
page.recompute()
d_doc.recompute()
else:
d_doc.recompute()
return body
def md_bck(c_sheet):
"""Make a bracket."""
md_bk_bw = c_sheet.get('md_bk_bw').Value
md_bk_hei = c_sheet.get('md_bk_hei').Value
md_bk_tpr = c_sheet.get('md_bk_tpr').Value
l1 = md_bk_bw * 0.50
c_cen = V3d(0.0, md_bk_hei, 0.0)
p1 = V3d(l1, 0.0, 0.0)
p2 = V3d(-l1, 0.0, 0.0)
tp1, tp2 = circle_tangent(md_bk_tpr, c_cen, p1)
d1 = p1.x - tp1.x
d2 = p1.x - tp2.x
if d1 < d2:
pt1 = tp1
else:
pt1 = tp2
l1 = Part.LineSegment(p1, pt1)
tp3, tp4 = circle_tangent(md_bk_tpr, c_cen, p2)
d3 = p2.x - tp3.x
d4 = p2.x - tp4.x
if d3 > d4:
pt2 = tp3
else:
pt2 = tp4
l2 = Part.LineSegment(p2, pt2)
cir = Part.Circle(c_cen, DVZ, md_bk_tpr)
par1 = cir.parameter(pt1)
par2 = cir.parameter(pt2)
arc = cir.toShape(par1, par2)
l3 = Part.LineSegment(p2, p1).toShape()
edges = [l1.toShape(), arc, l2.toShape(), l3]
return edges
if __name__ == "__main__":
# use 1 as suffix of ensure_document as 2 will crash the application.
doc_rname = ensure_document(DOC_Name, 1)
dest_doc = FreeCAD.activeDocument()
dest_doc.recompute()
sheet = init_doc_ss(dest_doc, True)
# model building
md_plat = main_body(dest_doc, "md_plat", sheet, 1)
dest_doc.recompute()
setview(doc_rname, 2)
in the example case, to make MeasureLabels (in my use case they will serve to show the customer what exact measure I need to have.)
Now I can get using the GUI that "object identifier" in my case wil be the center of
Carlo D.