FreeCAD-macros
422 строки · 15.3 Кб
1import FreeCAD as app2from FreeCAD import Vector, Rotation3import Draft4import BOPTools.JoinFeatures5
6
7def create_box(materialWidth,8boxWidth, boxHeight, boxLength,9notchWidth,10drawSides=[True, True, True, True, True, True],11overhangTop=[0.0, 0.0, 0.0, 0.0],12overhangBottom=[0.0, 0.0, 0.0, 0.0],13doc=None):14"""Create a box with interlocked notches.15
16Parameters
17----------
18- drawSides: [top, bottom, left, right, front, back]
19- overhangTop: [top left, top right, top front, top back]
20- overhangBottom: [bottom left, bottom right, bottom front, bottom back]
21"""
22
23if doc is None:24doc = app.activeDocument()25
26if doc is None:27doc = app.newDocument()28
29if doc is None:30app.Console.PrintError('Could not get a document where to create the box')31return32
33boxobjects = []34
35if drawSides[1]:36side1 = draw_top_bottom(doc, 'bottom', materialWidth, boxWidth, boxLength, notchWidth, drawSides, overhangBottom)37boxobjects.append(side1)38
39if drawSides[0]:40side2 = draw_top_bottom(doc, 'top', materialWidth, boxWidth, boxLength, notchWidth, drawSides, overhangTop)41side2.Placement.Base.z += boxHeight - materialWidth42boxobjects.append(side2)43
44if drawSides[2]:45side3 = draw_left_right(doc, 'left', materialWidth, boxHeight, boxLength, notchWidth, drawSides)46boxobjects.append(side3)47
48if drawSides[3]:49side4 = draw_left_right(doc, 'right', materialWidth, boxHeight, boxLength, notchWidth, drawSides)50Draft.move([side4], Vector(boxWidth - materialWidth, 0.0, 0.0), copy=False)51boxobjects.append(side4)52
53if drawSides[4]:54side5 = draw_front_back(doc, 'front', materialWidth, boxWidth, boxHeight, notchWidth, drawSides)55boxobjects.append(side5)56
57if drawSides[5]:58side6 = draw_front_back(doc, 'back', materialWidth, boxWidth, boxHeight, notchWidth, drawSides)59Draft.move([side6], Vector(0.0, boxLength - materialWidth, 0.0), copy=False)60boxobjects.append(side6)61
62comp1 = doc.addObject('Part::Compound', 'Box')63comp1.Links = boxobjects64
65doc.recompute()66return comp167
68
69def draw_top_bottom(doc, partname, materialWidth, boxWidth, boxLength, notchWidth, drawSides=[True, True, True, True, True, True], overhang=[0.0, 0.0, 0.0, 0.0]):70"""Create the top or bottom part of the box.71
72Parameters
73----------
74- drawSides = [top, bottom, left, right, front, back]
75- overhang = [left, right, front, back]
76"""
77lines = []78
79if overhang[2] > 0:80lines += _notch_holes(boxWidth, notchWidth, materialWidth, Vector(0, 0, 0), overhang[2], drawSides[4], overhang[0], overhang[1])81else:82lines.append(_notch_line(boxWidth, notchWidth, materialWidth, Vector(0, 0, 0), False, False, drawSides[4]))83
84if overhang[1] > 0:85lines2 = _notch_holes(boxLength, notchWidth, materialWidth, Vector(0, 0, 90), overhang[1], drawSides[3], overhang[2], overhang[2])86for line in lines2:87line.Placement.Base.x += boxWidth88lines.append(line)89else:90lines2 = _notch_line(boxLength, notchWidth, materialWidth, Vector(0, 0, 90), False, False, drawSides[3])91lines2.Placement.Base.x += boxWidth92lines.append(lines2)93
94if overhang[3] > 0:95lines3 = _notch_holes(boxWidth, notchWidth, materialWidth, Vector(0, 0, 180), overhang[3], drawSides[5], overhang[1], overhang[0])96for line in lines3:97line.Placement.Base.x += boxWidth98line.Placement.Base.y += boxLength99lines.append(line)100else:101lines3 = _notch_line(boxWidth, notchWidth, materialWidth, Vector(0, 0, 180), False, False, drawSides[5])102lines3.Placement.Base.x += boxWidth103lines3.Placement.Base.y += boxLength104lines.append(lines3)105
106if overhang[0] > 0:107lines4 = _notch_holes(boxLength, notchWidth, materialWidth, Vector(0, 0, 270), overhang[0], drawSides[2], overhang[3], overhang[3])108for line in lines4:109line.Placement.Base.y += boxLength110lines.append(line)111else:112lines4 = _notch_line(boxLength, notchWidth, materialWidth, Vector(0, 0, 270), False, False, drawSides[2])113lines4.Placement.Base.y += boxLength114lines.append(lines4)115
116doc.recompute()117side1 = _extrude_lines(doc, partname, lines, materialWidth)118return side1119
120
121def draw_left_right(doc, partname, materialWidth, boxHeight, boxLength, notchWidth, drawSides=[True, True, True, True, True, True]):122"""Create the left or right part of the box.123
124Also used to create the compartment separators inside the box.
125
126Parameters
127----------
128- drawSides = [top, bottom, left, right, front, back]
129"""
130line1 = _notch_line(boxLength, notchWidth, materialWidth, Vector(0, 270, 90), drawSides[4], drawSides[5], drawSides[1])131if drawSides[1]:132line1.Placement.Base.z += materialWidth133
134line2 = _notch_line(boxHeight, notchWidth, materialWidth, Vector(90, 90, 90), drawSides[1], drawSides[0], drawSides[4])135if drawSides[4]:136line2.Placement.Base.y += materialWidth137
138line3 = _notch_line(boxLength, notchWidth, materialWidth, Vector(0, 90, 90), drawSides[4], drawSides[5], drawSides[0])139line3.Placement.Base.z += boxHeight140if drawSides[0]:141line3.Placement.Base.z -= materialWidth142
143line4 = _notch_line(boxHeight, notchWidth, materialWidth, Vector(90, 270, 90), drawSides[1], drawSides[0], drawSides[5])144line4.Placement.Base.y += boxLength145if drawSides[5]:146line4.Placement.Base.y -= materialWidth147
148lines = [line1, line2, line3, line4]149
150side3 = _extrude_lines(doc, partname, lines, materialWidth)151return side3152
153
154def draw_front_back(doc, partname, materialWidth, boxWidth, boxHeight, notchWidth, drawSides=[True, True, True, True, True, True]):155"""Create the front or back part of the box."""156line1 = _notch_line(boxWidth, notchWidth, materialWidth, Vector(270, 0, 0), False, False, drawSides[1])157if drawSides[1]:158line1.Placement.Base.z += materialWidth159
160line2 = _notch_line(boxHeight, notchWidth, materialWidth, Vector(90, 0, 270), drawSides[0], drawSides[1], drawSides[2])161line2.Placement.Base.z += boxHeight162
163line3 = _notch_line(boxWidth, notchWidth, materialWidth, Vector(90, 0, 0), False, False, drawSides[0])164line3.Placement.Base.z += boxHeight165if drawSides[0]:166line3.Placement.Base.z -= materialWidth167
168line4 = _notch_line(boxHeight, notchWidth, materialWidth, Vector(90, 0, 90), drawSides[1], drawSides[0], drawSides[3])169line4.Placement.Base.x += boxWidth170
171doc.recompute()172lines = [line1, line2, line3, line4]173
174side5 = _extrude_lines(doc, partname, lines, materialWidth)175return side5176
177
178def _notch_line(length, notchWidth, materialWidth, rotation=Vector(0, 0, 0), insideLeft=False, insideRight=False, drawNotches=True):179"""Create the lines for the notches."""180if not drawNotches:181if insideLeft: x = materialWidth182else: x = 0183
184if insideRight: y = length - materialWidth185else: y = length186
187points = _rotate_points([Vector(x, 0.0, 0.0),188Vector(y, 0.0, 0.0)],189rotation)190
191line = Draft.makeWire(points, closed=False, face=False, support=None)192return line193
194nrNotches = int((length - 2 * materialWidth) / (notchWidth * 2))195edgeLen = (length - (notchWidth * (nrNotches * 2 - 1))) / 2196x = 0197if insideLeft:198x = materialWidth199edgeLen -= materialWidth200
201points = [Vector(x, 0, 0)]202x += edgeLen203for count in range(0, nrNotches):204points.append(Vector(x, 0, 0))205points.append(Vector(x, materialWidth, 0))206x = x + notchWidth207points.append(Vector(x, materialWidth, 0))208points.append(Vector(x, 0, 0))209x = x + notchWidth210
211if insideLeft and not insideRight:212edgeLen += materialWidth213
214points.append(Vector(x - notchWidth + edgeLen, 0, 0))215line = Draft.makeWire(_rotate_points(points, rotation), closed=False, face=False, support=None)216Draft.autogroup(line)217return line218
219
220def _draw_holes(length, notchWidth, materialWidth, rotation):221"""Create the lines for the notch holes in a part."""222lines = []223nrNotches = int((length - 2 * materialWidth) / (notchWidth * 2))224x = (length - (notchWidth * (nrNotches * 2 - 1))) / 2225for count in range(0, nrNotches):226points = [Vector(x, 0, 0), Vector(x, materialWidth, 0), Vector(x + notchWidth, materialWidth, 0), Vector(x + notchWidth, 0, 0)]227points = _rotate_points(points, rotation)228line = Draft.makeWire(points, closed=True, face=False, support=None)229line.Label = "hole"230Draft.autogroup(line)231lines.append(line)232x = x + notchWidth * 2233
234return lines235
236
237def _notch_holes(length, notchWidth, materialWidth, rotation=Vector(0, 0, 0), overhang=0, drawHoles=True, overhangLeft=0, overhangRight=0):238lines = []239
240if drawHoles:241lines = _draw_holes(length, notchWidth, materialWidth, rotation)242
243points = [Vector(-overhangLeft, 0, 0),244Vector(-overhangLeft, -overhang, 0),245Vector(length + overhangRight, -overhang, 0),246Vector(length + overhangRight, 0, 0)]247points = _rotate_points(points, rotation)248ohline = Draft.makeWire(points, closed=False, face=False, support=None)249lines.append(ohline)250return lines251
252
253def _extrude_lines(doc, extrudename, lines, materialWidth):254doc.recompute()255j = BOPTools.JoinFeatures.makeConnect(name='Outline')256j.Objects = lines257j.Proxy.execute(j)258j.purgeTouched()259for obj in j.ViewObject.Proxy.claimChildren():260obj.ViewObject.hide()261
262f = doc.addObject('Part::Extrusion', extrudename)263f.Base = j264f.DirMode = 'Normal'265f.DirLink = None266f.LengthFwd = materialWidth267f.LengthRev = 0268f.Solid = True269f.Reversed = False270f.Symmetric = False271f.TaperAngle = 0272f.TaperAngleRev = 0273f.Base.ViewObject.hide()274return f275
276
277def _rotate_points(plist, axisdegree):278"""Return a list of points rotated around the origin279
280The rotation is defined by three angles in degrees and the rotation order is
281z, y, x, each around the newly rotated axis.
282
283Parameters
284----------
285- plist: list of Vector.
286- axisdegree: Vector with angles in deg.
287"""
288newlist = []289for v in plist:290if axisdegree.z != 0:291rota = Rotation(Vector(0, 0, 1), axisdegree.z)292v = rota.multVec(v)293
294if axisdegree.y != 0:295rota = Rotation(Vector(0, 1, 0), axisdegree.y)296v = rota.multVec(v)297
298if axisdegree.x != 0:299rota = Rotation(Vector(1, 0, 0), axisdegree.x)300v = rota.multVec(v)301
302newlist.append(v)303
304return newlist305
306
307def create_compartment(box,308direction,309offset,310materialWidth,311notchWidth,312drawSides=[True, True, True, True, True, True],313boxsize=Vector(0, 0, 0)):314try:315doc = box[0].Document316except (IndexError, AttributeError) as e:317app.Console.PrintError(318'Could not get a document where to create the compartment: {}'.format(e))319return320
321cpos = direction * offset322mybox = None323if len(box) == 1 and hasattr(box[0], 'Links'):324parts = box[0].Links325mybox = box[0]326elif isinstance(box, list):327parts = box328else:329parts = [box]330
331if boxsize == Vector(0, 0, 0):332for side in parts:333if hasattr(side, 'Shape'):334bbox = side.Shape.BoundBox335if bbox.XLength > boxsize.x: boxsize.x = bbox.XLength336if bbox.YLength > boxsize.y: boxsize.y = bbox.YLength337if bbox.ZLength > boxsize.z: boxsize.z = bbox.ZLength338
339holes = []340if direction == Vector(1, 0, 0):341if boxsize.z == 0 or boxsize.y == 0:342app.Console.PrintError("select a box first !\n")343return344compartment = draw_left_right(doc, 'compartmentX' + str(offset), materialWidth, boxsize.z, boxsize.y, notchWidth, drawSides)345if drawSides[4] or drawSides[5]:346holes += _draw_holes(boxsize.y, notchWidth, materialWidth, Vector(0, 0, 90))347if drawSides[2] or drawSides[3]:348holes += _draw_holes(boxsize.z, notchWidth, materialWidth, Vector(90, 0, 90))349
350for h in holes:351h.Placement.Base.x += offset + materialWidth352
353elif direction == Vector(0, 1, 0):354if boxsize.z == 0 or boxsize.x == 0:355app.Console.PrintError("select a box first !\n")356return357
358sides = [drawSides[0], drawSides[1], drawSides[4], drawSides[5], drawSides[2], drawSides[3]]359compartment = draw_left_right(doc, 'compartmentY' + str(offset), materialWidth, boxsize.z, boxsize.x, notchWidth, sides)360doc.recompute()361Draft.rotate([compartment], 270.0, Vector(0, 0, 0), axis=Vector(0.0, 0.0, 1.0), copy=False)362doc.recompute()363Draft.move([compartment], Vector(0, materialWidth, 0), copy=False)364doc.recompute()365if drawSides[0] or drawSides[1]:366holes += _draw_holes(boxsize.x, notchWidth, materialWidth, Vector(0, 0, 0))367if drawSides[2] or drawSides[3]:368holes += _draw_holes(boxsize.z, notchWidth, materialWidth, Vector(0, 270, 0))369
370for h in holes:371h.Placement.Base.y += offset372
373elif direction == Vector(0, 0, 1):374if boxsize.x == 0 or boxsize.y == 0:375app.Console.PrintError("select a box first !\n")376return377
378sides = [drawSides[2], drawSides[3], drawSides[0], drawSides[1], drawSides[4], drawSides[5]]379compartment = draw_left_right(doc, 'compartmentZ' + str(offset), materialWidth, boxsize.x, boxsize.y, notchWidth, sides)380doc.recompute()381Draft.rotate([compartment], 270.0, Vector(boxsize.x, 0, 0), axis=Vector(0.0, 1.0, 0.0), copy=False)382doc.recompute()383Draft.move([compartment], Vector(0, 0, boxsize.x), copy=False)384doc.recompute()385if drawSides[0] or drawSides[1]:386holes += _draw_holes(boxsize.x, notchWidth, materialWidth, Vector(270, 0, 0))387if drawSides[4] or drawSides[5]:388holes += _draw_holes(boxsize.y, notchWidth, materialWidth, Vector(0, 270, 90))389
390for h in holes:391h.Placement.Base.z += offset + materialWidth392else:393return None394
395Draft.move([compartment], cpos, copy=False)396
397doc.recompute()398_add_lines_to_box_side(parts, holes)399
400if mybox:401parts.append(compartment)402mybox.Links = parts403doc.recompute()404return mybox405
406doc.recompute()407return compartment408
409
410def _add_lines_to_box_side(box, holes):411epsilon = 1e-7412for side in box:413if hasattr(side, 'Base') and hasattr(side.Base, 'Objects')and not side.Name.startswith("compartment"):414outline = side.Base415obox = outline.Shape.BoundBox416
417for h in holes:418h.ViewObject.hide()419hbox = h.Shape.BoundBox420if (hbox.XLength < epsilon and obox.XLength < epsilon) or (hbox.YLength < epsilon and obox.YLength < epsilon) or (hbox.ZLength < epsilon and obox.ZLength < epsilon):421outline.Objects += [h]422outline.Proxy.execute(outline)423