def execute(self,obj): if self.clone(obj): return pl = obj.Placement length = obj.Length.Value width = obj.Width.Value height = obj.Height.Value chamfer = obj.Chamfer.Value dentheight = obj.DentHeight.Value dentwidth = obj.DentWidth.Value if (length == 0) or (width == 0) or (height == 0): return if ((chamfer+dentwidth) >= width) or (dentheight >= height): return import Part p = [] p.append(Vector(0,0,0)) p.append(Vector(length,0,0)) p.append(Vector(length,width,0)) p.append(Vector(0,width,0)) p.append(p[0]) p = Part.makePolygon(p) f = Part.Face(p) shape = f.extrude(Vector(0,0,height)) if chamfer > 0: p = [] p.append(Vector(0,width-chamfer,0)) p.append(Vector(chamfer,width,0)) p.append(Vector(0,width,0)) p.append(p[0]) p = Part.makePolygon(p) f = Part.Face(p) s = f.extrude(Vector(0,0,height)) shape = shape.cut(s) p = [] p.append(Vector(length,width-chamfer,0)) p.append(Vector(length-chamfer,width,0)) p.append(Vector(length,width,0)) p.append(p[0]) p = Part.makePolygon(p) f = Part.Face(p) s = f.extrude(Vector(0,0,height)) shape = shape.cut(s) p = [] p.append(Vector(0,width-chamfer,0)) p.append(Vector(0,width,chamfer)) p.append(Vector(0,width,0)) p.append(p[0]) p = Part.makePolygon(p) f = Part.Face(p) s = f.extrude(Vector(length,0,0)) shape = shape.cut(s) p = [] p.append(Vector(0,width-chamfer,height)) p.append(Vector(0,width,height-chamfer)) p.append(Vector(0,width,height)) p.append(p[0]) p = Part.makePolygon(p) f = Part.Face(p) s = f.extrude(Vector(length,0,0)) shape = shape.cut(s) if (dentheight > 0) and (dentwidth > 0): p = [] p.append(Vector(0,((width-chamfer)-dentwidth)/2,0)) p.append(Vector(0,((width-chamfer)-dentwidth)/2+dentwidth,0)) p.append(Vector(0,((width-chamfer)-dentwidth)/2+dentwidth,dentheight)) p.append(Vector(0,((width-chamfer)-dentwidth)/2,dentheight)) p.append(p[0]) p = Part.makePolygon(p) f = Part.Face(p) s = f.extrude(Vector(length,0,0)) shape = shape.cut(s) s.translate(Vector(0,0,height)) shape = shape.fuse(s) shape = self.processSubShapes(obj,shape,pl) self.applyShape(obj,shape,pl)
def process(filename): """Process the filename and create a Draft Wire from the data. The common airfoil dat format has many flavors. This code should work with almost every dialect. Parameters ---------- filename : str The path to the filename to be opened. Returns ------- Part::Part2DObject or None. The created Draft Wire object or None if the file contains less than 3 points. """ # Regex to identify data rows and throw away unused metadata xval = r'(?P<xval>\-?\s*\d*\.*\d*([Ee]\-?\d+)?)' yval = r'(?P<yval>\-?\s*\d*\.*\d*([Ee]\-?\d+)?)' _regex = r'^\s*' + xval + r'\,?\s*' + yval + r'\s*$' regex = re.compile(_regex) afile = pythonopen(filename, 'r') # read the airfoil name which is always at the first line airfoilname = afile.readline().strip() coords = [] # upside = True # last_x = None # Collect the data for lin in afile: curdat = regex.match(lin) if (curdat is not None and curdat.group("xval") and curdat.group("yval")): x = float(curdat.group("xval")) y = float(curdat.group("yval")) # Some files specify the number of upper and lower points on the 2nd line: # " 67. 72." # See: http://airfoiltools.com/airfoil # This line must be skipped: if x < 2 and y < 2: # the normal processing coords.append(Vector(x, y, 0)) afile.close() if len(coords) < 3: FCC.PrintError(translate("ImportAirfoilDAT", "Did not find enough coordinates") + "\n") return None # sometimes coords are divided in upper an lower side # so that x-coordinate begin new from leading or trailing edge # check for start coordinates in the middle of list if coords[0:-1].count(coords[0]) > 1: flippoint = coords.index(coords[0], 1) upper = coords[0:flippoint] lower = coords[flippoint+1:] lower.reverse() for i in lower: upper.append(i) coords = upper # do we use the parametric Draft Wire? if useDraftWire: obj = Draft.make_wire(coords, True) # obj.label = airfoilname else: # alternate solution, uses common Part Faces lines = [] first_v = None last_v = None for v in coords: if first_v is None: first_v = v # Line between v and last_v if they're not equal if (last_v is not None) and (last_v != v): lines.append(Part.makeLine(last_v, v)) # The new last_v last_v = v # close the wire if needed if last_v != first_v: lines.append(Part.makeLine(last_v, first_v)) wire = Part.Wire(lines) face = Part.Face(wire) obj = FreeCAD.ActiveDocument.addObject('Part::Feature', airfoilname) obj.Shape = face return obj
import draftguitools.gui_arrays import draftguitools.gui_annotationstyleeditor from draftguitools.gui_layers import Layer # --------------------------------------------------------------------------- # Preflight stuff # --------------------------------------------------------------------------- # update the translation engine FreeCADGui.updateLocale() # sets the default working plane plane = WorkingPlane.plane() FreeCAD.DraftWorkingPlane = plane defaultWP = Draft.getParam("defaultWP", 0) if defaultWP == 1: plane.alignToPointAndAxis(Vector(0, 0, 0), Vector(0, 0, 1), 0) elif defaultWP == 2: plane.alignToPointAndAxis(Vector(0, 0, 0), Vector(0, 1, 0), 0) elif defaultWP == 3: plane.alignToPointAndAxis(Vector(0, 0, 0), Vector(1, 0, 0), 0) # last snapped objects, for quick intersection calculation lastObj = [0, 0] # Set modifier keys from draftguitools.gui_tool_utils import MODCONSTRAIN from draftguitools.gui_tool_utils import MODSNAP from draftguitools.gui_tool_utils import MODALT # --------------------------------------------------------------------------- # General functions
def getDeviation(self): """Return a deviation vector that represents the base of the circle.""" import Part c = Part.makeCircle(1, Vector(0, 0, 0), self.normal) return c.Vertexes[0].Point
def alignToPointAndAxis_SVG(self, point, axis, offset=0): """Align the working plane to a point and an axis (vector). It aligns `u` and `v` based on the magnitude of the components of `axis`. Also set `weak` to `False`. Parameters ---------- point : Base::Vector3 The new `position` of the plane, adjusted by the `offset`. axis : Base::Vector3 A vector whose unit vector will be used as the new `axis` of the plane. The magnitudes of the `x`, `y`, `z` components of the axis determine the orientation of `u` and `v` of the plane. offset : float, optional Defaults to zero. A value which will be used to offset the plane in the direction of its `axis`. Cases ----- The `u` and `v` are always calculated the same * `u` is the cross product of the positive or negative of `axis` with a `reference vector`. :: u = [+1|-1] axis.cross(ref_vec) * `v` is `u` rotated 90 degrees around `axis`. Whether the `axis` is positive or negative, and which reference vector is used, depends on the absolute values of the `x`, `y`, `z` components of the `axis` unit vector. #. If `x > y`, and `y > z` The reference vector is +Z :: u = -1 axis.cross(+Z) #. If `y > z`, and `z >= x` The reference vector is +X. :: u = -1 axis.cross(+X) #. If `y >= x`, and `x > z` The reference vector is +Z. :: u = +1 axis.cross(+Z) #. If `x > z`, and `z >= y` The reference vector is +Y. :: u = +1 axis.cross(+Y) #. If `z >= y`, and `y > x` The reference vector is +X. :: u = +1 axis.cross(+X) #. otherwise The reference vector is +Y. :: u = -1 axis.cross(+Y) """ self.doc = FreeCAD.ActiveDocument self.axis = axis self.axis.normalize() ref_vec = Vector(0.0, 1.0, 0.0) if ((abs(axis.x) > abs(axis.y)) and (abs(axis.y) > abs(axis.z))): ref_vec = Vector(0.0, 0., 1.0) self.u = axis.negative().cross(ref_vec) self.u.normalize() self.v = DraftVecUtils.rotate(self.u, math.pi / 2, self.axis) # projcase = "Case new" elif ((abs(axis.y) > abs(axis.z)) and (abs(axis.z) >= abs(axis.x))): ref_vec = Vector(1.0, 0.0, 0.0) self.u = axis.negative().cross(ref_vec) self.u.normalize() self.v = DraftVecUtils.rotate(self.u, math.pi / 2, self.axis) # projcase = "Y>Z, View Y" elif ((abs(axis.y) >= abs(axis.x)) and (abs(axis.x) > abs(axis.z))): ref_vec = Vector(0.0, 0., 1.0) self.u = axis.cross(ref_vec) self.u.normalize() self.v = DraftVecUtils.rotate(self.u, math.pi / 2, self.axis) # projcase = "ehem. XY, Case XY" elif ((abs(axis.x) > abs(axis.z)) and (abs(axis.z) >= abs(axis.y))): self.u = axis.cross(ref_vec) self.u.normalize() self.v = DraftVecUtils.rotate(self.u, math.pi / 2, self.axis) # projcase = "X>Z, View X" elif ((abs(axis.z) >= abs(axis.y)) and (abs(axis.y) > abs(axis.x))): ref_vec = Vector(1.0, 0., 0.0) self.u = axis.cross(ref_vec) self.u.normalize() self.v = DraftVecUtils.rotate(self.u, math.pi / 2, self.axis) # projcase = "Y>X, Case YZ" else: self.u = axis.negative().cross(ref_vec) self.u.normalize() self.v = DraftVecUtils.rotate(self.u, math.pi / 2, self.axis) # projcase = "else" # spat_vec = self.u.cross(self.v) # spat_res = spat_vec.dot(axis) # Console.PrintMessage(projcase + " spat Prod = " + str(spat_res) + "\n") offsetVector = Vector(axis) offsetVector.multiply(offset) self.position = point.add(offsetVector) self.weak = False
def p1(self, point=None): """Set or get the base point of the rectangle.""" if point: self.setorigin(point) else: return Vector(self.coords.point.getValues()[0].getValue())
def p3(self, point=None): """Set or get the opposite (diagonal) point of the rectangle.""" if point: self.update(point) else: return Vector(self.coords.point.getValues()[2].getValue())
def _create_objects(doc=None, font_file="/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf" ): """Create the objects of the test file. Parameters ---------- doc: App::Document, optional It defaults to `None`, which then defaults to the current active document, or creates a new document. """ if not doc: doc = App.activeDocument() if not doc: doc = App.newDocument() # Line, wire, and fillet _msg(16 * "-") _msg("Line") Draft.make_line(Vector(0, 0, 0), Vector(500, 500, 0)) t_xpos = -50 t_ypos = -200 _set_text(["Line"], Vector(t_xpos, t_ypos, 0)) _msg(16 * "-") _msg("Wire") Draft.make_wire( [Vector(500, 0, 0), Vector(1000, 500, 0), Vector(1000, 1000, 0)]) t_xpos += 500 _set_text(["Wire"], Vector(t_xpos, t_ypos, 0)) _msg(16 * "-") _msg("Fillet") line_h_1 = Draft.make_line(Vector(1500, 0, 0), Vector(1500, 500, 0)) line_h_2 = Draft.make_line(Vector(1500, 500, 0), Vector(2000, 500, 0)) if App.GuiUp: line_h_1.ViewObject.DrawStyle = "Dotted" line_h_2.ViewObject.DrawStyle = "Dotted" doc.recompute() Draft.make_fillet([line_h_1, line_h_2], 400) t_xpos += 900 _set_text(["Fillet"], Vector(t_xpos, t_ypos, 0)) # Circle, arc, arc by 3 points _msg(16 * "-") _msg("Circle") circle = Draft.make_circle(350) circle.Placement.Base = Vector(2500, 500, 0) t_xpos += 1050 _set_text(["Circle"], Vector(t_xpos, t_ypos, 0)) _msg(16 * "-") _msg("Circular arc") arc = Draft.make_circle(350, startangle=0, endangle=100) arc.Placement.Base = Vector(3200, 500, 0) t_xpos += 800 _set_text(["Circular arc"], Vector(t_xpos, t_ypos, 0)) _msg(16 * "-") _msg("Circular arc 3 points") Draft.make_arc_3points( [Vector(4600, 0, 0), Vector(4600, 800, 0), Vector(4000, 1000, 0)]) t_xpos += 600 _set_text(["Circular arc 3 points"], Vector(t_xpos, t_ypos, 0)) # Ellipse, polygon, rectangle _msg(16 * "-") _msg("Ellipse") ellipse = Draft.make_ellipse(500, 300) ellipse.Placement.Base = Vector(5500, 250, 0) t_xpos += 1600 _set_text(["Ellipse"], Vector(t_xpos, t_ypos, 0)) _msg(16 * "-") _msg("Polygon") polygon = Draft.make_polygon(5, 250) polygon.Placement.Base = Vector(6500, 500, 0) t_xpos += 950 _set_text(["Polygon"], Vector(t_xpos, t_ypos, 0)) _msg(16 * "-") _msg("Rectangle") rectangle = Draft.make_rectangle(500, 1000, 0) rectangle.Placement.Base = Vector(7000, 0, 0) t_xpos += 650 _set_text(["Rectangle"], Vector(t_xpos, t_ypos, 0)) # Text _msg(16 * "-") _msg("Text") text = Draft.make_text(["Testing", "text"], Vector(7700, 500, 0)) if App.GuiUp: text.ViewObject.FontSize = 100 t_xpos += 700 _set_text(["Text"], Vector(t_xpos, t_ypos, 0)) # Linear dimension _msg(16 * "-") _msg("Linear dimension") line = Draft.make_wire([Vector(8700, 200, 0), Vector(8700, 1200, 0)]) dimension = Draft.make_linear_dimension(Vector(8600, 200, 0), Vector(8600, 1000, 0), Vector(8400, 750, 0)) if App.GuiUp: dimension.ViewObject.ArrowSize = 15 dimension.ViewObject.ExtLines = 1000 dimension.ViewObject.ExtOvershoot = 100 dimension.ViewObject.DimOvershoot = 50 dimension.ViewObject.FontSize = 100 dimension.ViewObject.ShowUnit = False doc.recompute() dim_obj = Draft.make_linear_dimension_obj(line, 1, 2, Vector(9000, 750, 0)) if App.GuiUp: dim_obj.ViewObject.ArrowSize = 15 dim_obj.ViewObject.ArrowType = "Arrow" dim_obj.ViewObject.ExtLines = 100 dim_obj.ViewObject.ExtOvershoot = 100 dim_obj.ViewObject.DimOvershoot = 50 dim_obj.ViewObject.FontSize = 100 dim_obj.ViewObject.ShowUnit = False t_xpos += 680 _set_text(["Dimension"], Vector(t_xpos, t_ypos, 0)) # Radius and diameter dimension _msg(16 * "-") _msg("Radius and diameter dimension") arc_h = Draft.make_circle(500, startangle=0, endangle=90) arc_h.Placement.Base = Vector(9500, 0, 0) doc.recompute() dimension_r = Draft.make_radial_dimension_obj(arc_h, 1, "radius", Vector(9750, 200, 0)) if App.GuiUp: dimension_r.ViewObject.ArrowSize = 15 dimension_r.ViewObject.FontSize = 100 dimension_r.ViewObject.ShowUnit = False arc_h2 = Draft.make_circle(450, startangle=-120, endangle=80) arc_h2.Placement.Base = Vector(10000, 1000, 0) doc.recompute() dimension_d = Draft.make_radial_dimension_obj(arc_h2, 1, "diameter", Vector(10750, 900, 0)) if App.GuiUp: dimension_d.ViewObject.ArrowSize = 15 dimension_d.ViewObject.FontSize = 100 dimension_d.ViewObject.ShowUnit = False t_xpos += 950 _set_text(["Radius dimension", "Diameter dimension"], Vector(t_xpos, t_ypos, 0)) # Angular dimension _msg(16 * "-") _msg("Angular dimension") Draft.make_line(Vector(10500, 300, 0), Vector(11500, 1000, 0)) Draft.make_line(Vector(10500, 300, 0), Vector(11500, 0, 0)) angle1 = -20 angle2 = 40 dimension_a = Draft.make_angular_dimension(Vector(10500, 300, 0), [angle1, angle2], Vector(11500, 300, 0)) if App.GuiUp: dimension_a.ViewObject.ArrowSize = 15 dimension_a.ViewObject.FontSize = 100 t_xpos += 1700 _set_text(["Angle dimension"], Vector(t_xpos, t_ypos, 0)) # BSpline _msg(16 * "-") _msg("BSpline") Draft.make_bspline([ Vector(12500, 0, 0), Vector(12500, 500, 0), Vector(13000, 500, 0), Vector(13000, 1000, 0) ]) t_xpos += 1500 _set_text(["BSpline"], Vector(t_xpos, t_ypos, 0)) # Point _msg(16 * "-") _msg("Point") point = Draft.make_point(13500, 500, 0) if App.GuiUp: point.ViewObject.PointSize = 10 t_xpos += 900 _set_text(["Point"], Vector(t_xpos, t_ypos, 0)) # Shapestring _msg(16 * "-") _msg("Shapestring") try: shape_string = Draft.make_shapestring("Testing", font_file, 100) shape_string.Placement.Base = Vector(14000, 500) except Exception: _wrn("Shapestring could not be created") _wrn("Possible cause: the font file may not exist") _wrn(font_file) rect = Draft.make_rectangle(500, 100) rect.Placement.Base = Vector(14000, 500) t_xpos += 600 _set_text(["Shapestring"], Vector(t_xpos, t_ypos, 0)) # Facebinder _msg(16 * "-") _msg("Facebinder") box = doc.addObject("Part::Box", "Cube") box.Length = 200 box.Width = 500 box.Height = 100 box.Placement.Base = Vector(15000, 0, 0) if App.GuiUp: box.ViewObject.Visibility = False facebinder = Draft.make_facebinder([(box, ("Face1", "Face3", "Face6"))]) facebinder.Extrusion = 10 t_xpos += 780 _set_text(["Facebinder"], Vector(t_xpos, t_ypos, 0)) # Cubic bezier curve, n-degree bezier curve _msg(16 * "-") _msg("Cubic bezier") Draft.make_bezcurve([ Vector(15500, 0, 0), Vector(15578, 485, 0), Vector(15879, 154, 0), Vector(15975, 400, 0), Vector(16070, 668, 0), Vector(16423, 925, 0), Vector(16500, 500, 0) ], degree=3) t_xpos += 680 _set_text(["Cubic bezier"], Vector(t_xpos, t_ypos, 0)) _msg(16 * "-") _msg("N-degree bezier") Draft.make_bezcurve([ Vector(16500, 0, 0), Vector(17000, 500, 0), Vector(17500, 500, 0), Vector(17500, 1000, 0), Vector(17000, 1000, 0), Vector(17063, 1256, 0), Vector(17732, 1227, 0), Vector(17790, 720, 0), Vector(17702, 242, 0) ]) t_xpos += 1200 _set_text(["n-Bezier"], Vector(t_xpos, t_ypos, 0)) # Label _msg(16 * "-") _msg("Label") place = App.Placement(Vector(18500, 500, 0), App.Rotation()) label = Draft.make_label(target_point=Vector(18000, 0, 0), placement=place, custom_text="Example label", distance=-250) label.Text = "Testing" if App.GuiUp: label.ViewObject.ArrowSize = 15 label.ViewObject.TextSize = 100 doc.recompute() t_xpos += 1200 _set_text(["Label"], Vector(t_xpos, t_ypos, 0)) # Orthogonal array and orthogonal link array _msg(16 * "-") _msg("Orthogonal array") rect_h = Draft.make_rectangle(500, 500) rect_h.Placement.Base = Vector(1500, 2500, 0) if App.GuiUp: rect_h.ViewObject.Visibility = False Draft.make_ortho_array(rect_h, Vector(600, 0, 0), Vector(0, 600, 0), Vector(0, 0, 0), 3, 2, 1, use_link=False) t_xpos = 1700 t_ypos = 2200 _set_text(["Array"], Vector(t_xpos, t_ypos, 0)) rect_h_2 = Draft.make_rectangle(500, 100) rect_h_2.Placement.Base = Vector(1500, 5000, 0) if App.GuiUp: rect_h_2.ViewObject.Visibility = False _msg(16 * "-") _msg("Orthogonal link array") Draft.make_ortho_array(rect_h_2, Vector(800, 0, 0), Vector(0, 500, 0), Vector(0, 0, 0), 2, 4, 1, use_link=True) t_ypos += 2600 _set_text(["Link array"], Vector(t_xpos, t_ypos, 0)) # Polar array and polar link array _msg(16 * "-") _msg("Polar array") wire_h = Draft.make_wire([ Vector(5500, 3000, 0), Vector(6000, 3500, 0), Vector(6000, 3200, 0), Vector(5800, 3200, 0) ]) if App.GuiUp: wire_h.ViewObject.Visibility = False Draft.make_polar_array(wire_h, 8, 200, Vector(5000, 3000, 0), use_link=False) t_xpos = 4600 t_ypos = 2200 _set_text(["Polar array"], Vector(t_xpos, t_ypos, 0)) _msg(16 * "-") _msg("Polar link array") wire_h_2 = Draft.make_wire([ Vector(5500, 6000, 0), Vector(6000, 6000, 0), Vector(5800, 5700, 0), Vector(5800, 5750, 0) ]) if App.GuiUp: wire_h_2.ViewObject.Visibility = False Draft.make_polar_array(wire_h_2, 8, 200, Vector(5000, 6000, 0), use_link=True) t_ypos += 3200 _set_text(["Polar link array"], Vector(t_xpos, t_ypos, 0)) # Circular array and circular link array _msg(16 * "-") _msg("Circular array") poly_h = Draft.make_polygon(5, 200) poly_h.Placement.Base = Vector(8000, 3000, 0) if App.GuiUp: poly_h.ViewObject.Visibility = False Draft.make_circular_array(poly_h, 500, 600, 3, 1, Vector(0, 0, 1), Vector(0, 0, 0), use_link=False) t_xpos = 7700 t_ypos = 1700 _set_text(["Circular array"], Vector(t_xpos, t_ypos, 0)) _msg(16 * "-") _msg("Circular link array") poly_h_2 = Draft.make_polygon(6, 150) poly_h_2.Placement.Base = Vector(8000, 6250, 0) if App.GuiUp: poly_h_2.ViewObject.Visibility = False Draft.make_circular_array(poly_h_2, 550, 450, 3, 1, Vector(0, 0, 1), Vector(0, 0, 0), use_link=True) t_ypos += 3100 _set_text(["Circular link array"], Vector(t_xpos, t_ypos, 0)) # Path array and path link array _msg(16 * "-") _msg("Path array") poly_h = Draft.make_polygon(3, 250) poly_h.Placement.Base = Vector(10000, 3000, 0) if App.GuiUp: poly_h.ViewObject.Visibility = False bspline_path = Draft.make_bspline([ Vector(10500, 2500, 0), Vector(11000, 3000, 0), Vector(11500, 3200, 0), Vector(12000, 4000, 0) ]) Draft.make_path_array(poly_h, bspline_path, 5, use_link=False) t_xpos = 10400 t_ypos = 2200 _set_text(["Path array"], Vector(t_xpos, t_ypos, 0)) _msg(16 * "-") _msg("Path link array") poly_h_2 = Draft.make_polygon(4, 200) poly_h_2.Placement.Base = Vector(10000, 5000, 0) if App.GuiUp: poly_h_2.ViewObject.Visibility = False bspline_path_2 = Draft.make_bspline([ Vector(10500, 4500, 0), Vector(11000, 6800, 0), Vector(11500, 6000, 0), Vector(12000, 5200, 0) ]) Draft.make_path_array(poly_h_2, bspline_path_2, 6, use_link=True) t_ypos += 2000 _set_text(["Path link array"], Vector(t_xpos, t_ypos, 0)) # Point array _msg(16 * "-") _msg("Point array") poly_h = Draft.make_polygon(3, 250) poly_h.Placement.Base = Vector(12500, 2500, 0) point_1 = Draft.make_point(13000, 3000, 0) point_2 = Draft.make_point(13000, 3500, 0) point_3 = Draft.make_point(14000, 2500, 0) point_4 = Draft.make_point(14000, 3000, 0) add_list, delete_list = Draft.upgrade([point_1, point_2, point_3, point_4]) compound = add_list[0] if App.GuiUp: compound.ViewObject.PointSize = 5 Draft.make_point_array(poly_h, compound) t_xpos = 13000 t_ypos = 2200 _set_text(["Point array"], Vector(t_xpos, t_ypos, 0)) # Clone and mirror _msg(16 * "-") _msg("Clone") wire_h = Draft.make_wire([ Vector(15000, 2500, 0), Vector(15200, 3000, 0), Vector(15500, 2500, 0), Vector(15200, 2300, 0) ]) Draft.make_clone(wire_h, Vector(0, 1000, 0)) t_xpos = 15000 t_ypos = 2100 _set_text(["Clone"], Vector(t_xpos, t_ypos, 0)) _msg(16 * "-") _msg("Mirror") wire_h = Draft.make_wire([ Vector(17000, 2500, 0), Vector(16500, 4000, 0), Vector(16000, 2700, 0), Vector(16500, 2500, 0), Vector(16700, 2700, 0) ]) Draft.mirror(wire_h, Vector(17100, 2000, 0), Vector(17100, 4000, 0)) t_xpos = 17000 t_ypos = 2200 _set_text(["Mirror"], Vector(t_xpos, t_ypos, 0)) doc.recompute()
def setup(doc=None, solvertype="ccxtools"): # setup model if doc is None: doc = init_doc() # geometry objects # bottom box bottom_box_obj = doc.addObject("Part::Box", "BottomBox") bottom_box_obj.Length = 100 bottom_box_obj.Width = 25 bottom_box_obj.Height = 500 bottom_box_obj.Placement = FreeCAD.Placement( Vector(186, 0, -247), Rotation(0, 0, 0), Vector(0, 0, 0), ) doc.recompute() # top half cylinder, https://forum.freecadweb.org/viewtopic.php?f=18&t=43001#p366111 top_halfcyl_obj = doc.addObject("Part::Cylinder", "TopHalfCylinder") top_halfcyl_obj.Radius = 30 top_halfcyl_obj.Height = 500 top_halfcyl_obj.Angle = 180 top_halfcyl_sh = Part.getShape(top_halfcyl_obj, '', needSubElement=False, refine=True) top_halfcyl_obj.Shape = top_halfcyl_sh top_halfcyl_obj.Placement = FreeCAD.Placement( Vector(0, -42, 0), Rotation(0, 90, 0), Vector(0, 0, 0), ) doc.recompute() # all geom fusion geom_obj = doc.addObject("Part::MultiFuse", "AllGeomFusion") geom_obj.Shapes = [bottom_box_obj, top_halfcyl_obj] if FreeCAD.GuiUp: bottom_box_obj.ViewObject.hide() top_halfcyl_obj.ViewObject.hide() doc.recompute() if FreeCAD.GuiUp: geom_obj.ViewObject.Document.activeView().viewAxonometric() geom_obj.ViewObject.Document.activeView().fitAll() # analysis analysis = ObjectsFem.makeAnalysis(doc, "Analysis") # solver if solvertype == "calculix": solver_object = analysis.addObject( ObjectsFem.makeSolverCalculix(doc, "SolverCalculiX"))[0] elif solvertype == "ccxtools": solver_object = analysis.addObject( ObjectsFem.makeSolverCalculixCcxTools(doc, "CalculiXccxTools"))[0] solver_object.WorkingDir = u"" if solvertype == "calculix" or solvertype == "ccxtools": solver_object.AnalysisType = "static" solver_object.GeometricalNonlinearity = "linear" solver_object.ThermoMechSteadyState = False solver_object.MatrixSolverType = "default" solver_object.IterationsControlParameterTimeUse = False solver_object.SplitInputWriter = False """ # solver parameter from fandaL, but they are not needed (see forum topic) solver_object.IterationsControlParameterTimeUse = True solver_object.IterationsControlParameterCutb = '0.25,0.5,0.75,0.85,,,1.5,' solver_object.IterationsControlParameterIter = '4,8,9,200,10,400,,200,,' solver_object.IterationsUserDefinedTimeStepLength = True solver_object.TimeInitialStep = 0.1 solver_object.TimeEnd = 1.0 solver_object.IterationsUserDefinedIncrementations = True # parameter DIRECT """ # material material_obj = analysis.addObject( ObjectsFem.makeMaterialSolid(doc, "MechanicalMaterial"))[0] mat = material_obj.Material mat["Name"] = "Steel-Generic" mat["YoungsModulus"] = "200000 MPa" mat["PoissonRatio"] = "0.30" material_obj.Material = mat analysis.addObject(material_obj) # constraint fixed con_fixed = analysis.addObject( ObjectsFem.makeConstraintFixed(doc, "ConstraintFixed"))[0] con_fixed.References = [ (geom_obj, "Face5"), (geom_obj, "Face6"), (geom_obj, "Face8"), (geom_obj, "Face9"), ] # constraint pressure con_pressure = analysis.addObject( ObjectsFem.makeConstraintPressure(doc, name="ConstraintPressure"))[0] con_pressure.References = [(geom_obj, "Face10")] con_pressure.Pressure = 100.0 # Pa ? = 100 Mpa ? con_pressure.Reversed = False # constraint contact con_contact = doc.Analysis.addObject( ObjectsFem.makeConstraintContact(doc, name="ConstraintContact"))[0] con_contact.References = [ (geom_obj, "Face7"), # first seams slave face, TODO proof in writer code! (geom_obj, "Face3"), # second seams master face, TODO proof in writer code! ] con_contact.Friction = 0.0 con_contact.Slope = 1000000.0 # contact stiffness 1000000.0 kg/(mm*s^2) # mesh from .meshes.mesh_contact_box_halfcylinder_tetra10 import create_nodes, create_elements fem_mesh = Fem.FemMesh() control = create_nodes(fem_mesh) if not control: FreeCAD.Console.PrintError("Error on creating nodes.\n") control = create_elements(fem_mesh) if not control: FreeCAD.Console.PrintError("Error on creating elements.\n") femmesh_obj = analysis.addObject(ObjectsFem.makeMeshGmsh(doc, mesh_name))[0] femmesh_obj.FemMesh = fem_mesh femmesh_obj.Part = geom_obj femmesh_obj.SecondOrderLinear = False doc.recompute() return doc
def pointsH(H, W, D, t1, t2, t3): p1 = Vector(0, 0, 0) p2 = Vector(W, 0, 0) p3 = Vector(W, t2, 0) p4 = Vector(W / 2 + t1 / 2, t2, 0) p5 = Vector(W / 2 + t1 / 2, H - t3, 0) p6 = Vector(W / 2 + D / 2, H - t3, 0) p7 = Vector(W / 2 + D / 2, H, 0) p8 = Vector(W / 2 - D / 2, H, 0) p9 = Vector(W / 2 - D / 2, H - t3, 0) p10 = Vector(W / 2 - t1 / 2, H - t3, 0) p11 = Vector(W / 2 - t1 / 2, t2, 0) p12 = Vector(0, t2, 0) return [p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p1]
def pointsOmega(H, W, D, t1, t2, t3): p1 = Vector(0, 0, 0) p2 = Vector(W, 0, 0) p3 = Vector(W, H - t3, 0) p4 = Vector(W + D - t1, H - t3, 0) p5 = Vector(W + D - t1, H, 0) p6 = Vector(W - t1, H, 0) p7 = Vector(W - t1, t2, 0) p8 = Vector(t1, t2, 0) p9 = Vector(t1, H, 0) p10 = Vector(t1 - D, H, 0) p11 = Vector(t1 - D, H - t3, 0) p12 = Vector(0, H - t3, 0) return [p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p1]
def setup(doc=None, solvertype="ccxtools"): if doc is None: doc = init_doc() # geometry object # name is important because the other method in this module use obj name l1 = Part.makeLine((-142.5, -142.5, 0), (142.5, -142.5, 0)) l2 = Part.makeLine((142.5, -142.5, 0), (142.5, 142.5, 0)) l3 = Part.makeLine((142.5, 142.5, 0), (-142.5, 142.5, 0)) l4 = Part.makeLine((-142.5, 142.5, 0), (-142.5, -142.5, 0)) wire = Part.Wire([l1, l2, l3, l4]) shape = wire.extrude(Vector(0, 0, 1000)) geom_obj = doc.addObject('Part::Feature', 'SquareTube') geom_obj.Shape = shape doc.recompute() if FreeCAD.GuiUp: geom_obj.ViewObject.Document.activeView().viewAxonometric() geom_obj.ViewObject.Document.activeView().fitAll() # analysis analysis = ObjectsFem.makeAnalysis(doc, "Analysis") # solver if solvertype == "calculix": solver_object = analysis.addObject( ObjectsFem.makeSolverCalculix(doc, "SolverCalculiX") )[0] elif solvertype == "ccxtools": solver_object = analysis.addObject( ObjectsFem.makeSolverCalculixCcxTools(doc, "CalculiXccxTools") )[0] solver_object.WorkingDir = u"" else: FreeCAD.Console.PrintWarning( "Not known or not supported solver type: {}. " "No solver object was created.\n".format(solvertype) ) if solvertype == "calculix" or solvertype == "ccxtools": solver_object.SplitInputWriter = False solver_object.AnalysisType = "static" solver_object.GeometricalNonlinearity = "linear" solver_object.ThermoMechSteadyState = False solver_object.MatrixSolverType = "default" solver_object.IterationsControlParameterTimeUse = False # shell thickness thickness = analysis.addObject( ObjectsFem.makeElementGeometry2D(doc, 0, "ShellThickness") )[0] thickness.Thickness = 15.0 # material material_object = analysis.addObject( ObjectsFem.makeMaterialSolid(doc, "FemMaterial") )[0] mat = material_object.Material mat["Name"] = "Steel-Generic" mat["YoungsModulus"] = "200000 MPa" mat["PoissonRatio"] = "0.30" mat["Density"] = "7900 kg/m^3" material_object.Material = mat # fixed_constraint fixed_constraint = analysis.addObject( ObjectsFem.makeConstraintFixed(doc, name="ConstraintFixed"))[0] fixed_constraint.References = [ (doc.SquareTube, "Edge4"), (doc.SquareTube, "Edge7"), (doc.SquareTube, "Edge10"), (doc.SquareTube, "Edge12")] # force_constraint1 force_constraint1 = analysis.addObject( ObjectsFem.makeConstraintForce(doc, name="ConstraintForce1"))[0] force_constraint1.References = [(doc.SquareTube, "Edge9")] force_constraint1.Force = 100000.00 force_constraint1.Direction = (doc.SquareTube, ["Edge9"]) force_constraint1.Reversed = True # force_constraint2 force_constraint2 = analysis.addObject( ObjectsFem.makeConstraintForce(doc, name="ConstraintForce2"))[0] force_constraint2.References = [(doc.SquareTube, "Edge3")] force_constraint2.Force = 100000.00 force_constraint2.Direction = (doc.SquareTube, ["Edge3"]) force_constraint2.Reversed = True # force_constraint3 force_constraint3 = analysis.addObject( ObjectsFem.makeConstraintForce(doc, name="ConstraintForce3"))[0] force_constraint3.References = [(doc.SquareTube, "Edge11")] force_constraint3.Force = 100000.00 force_constraint3.Direction = (doc.SquareTube, ["Edge11"]) force_constraint3.Reversed = True # force_constraint4 force_constraint4 = analysis.addObject( ObjectsFem.makeConstraintForce(doc, name="ConstraintForce4"))[0] force_constraint4.References = [(doc.SquareTube, "Edge6")] force_constraint4.Force = 100000.00 force_constraint4.Direction = (doc.SquareTube, ["Edge6"]) force_constraint4.Reversed = True # mesh from .meshes.mesh_square_pipe_end_twisted_tria6 import create_nodes, create_elements fem_mesh = Fem.FemMesh() control = create_nodes(fem_mesh) if not control: FreeCAD.Console.PrintError("Error on creating nodes.\n") control = create_elements(fem_mesh) if not control: FreeCAD.Console.PrintError("Error on creating elements.\n") femmesh_obj = analysis.addObject( ObjectsFem.makeMeshGmsh(doc, mesh_name) )[0] femmesh_obj.FemMesh = fem_mesh femmesh_obj.Part = geom_obj femmesh_obj.SecondOrderLinear = False doc.recompute() return doc
def execute(self,obj): if self.clone(obj): return pl = obj.Placement length = obj.Length.Value width = obj.Width.Value height = obj.Height.Value chamfer = obj.Chamfer.Value dentlength = obj.DentLength.Value dentheight = obj.DentHeight.Value dents = obj.Dents if (length == 0) or (width == 0) or (height == 0): return if (chamfer >= width/2) or (chamfer >= height/2): return import Part p = [] if chamfer > 0: p.append(Vector(0,chamfer,0)) p.append(Vector(0,width-chamfer,0)) p.append(Vector(0,width,chamfer)) p.append(Vector(0,width,height-chamfer)) p.append(Vector(0,width-chamfer,height)) p.append(Vector(0,chamfer,height)) p.append(Vector(0,0,height-chamfer)) p.append(Vector(0,0,chamfer)) else: p.append(Vector(0,0,0)) p.append(Vector(0,width,0)) p.append(Vector(0,width,height)) p.append(Vector(0,0,height)) p.append(p[0]) p = Part.makePolygon(p) f = Part.Face(p) shape = f.extrude(Vector(length,0,0)) if (dentlength > 0) and (dentheight > 0): p = [] p.append(Vector(0,0,0)) p.append(Vector(dentlength,0,0)) p.append(Vector(dentlength,width,0)) p.append(Vector(0,width,0)) p.append(p[0]) p = Part.makePolygon(p) f = Part.Face(p) d1 = f.extrude(Vector(0,0,dentheight)) d2 = d1.copy() d2.translate(Vector(length-dentlength,0,0)) shape = shape.cut(d1) shape = shape.cut(d2) for dent in dents: dent = dent.split(";") if len(dent) == 7: dentlength = float(dent[0]) dentwidth = float(dent[1]) dentheight = float(dent[2]) dentslant = float(dent[3]) dentchamfer = chamfer dentlevel = float(dent[4]) dentrotation = float(dent[5]) dentoffset = float(dent[6]) if (dentlength == 0) or (dentwidth == 0) or (dentheight == 0): continue if dentslant >= dentheight: continue p = [] p.append(Vector(0-dentchamfer,0,0)) p.append(Vector(dentlength,0,dentslant)) p.append(Vector(dentlength,0,dentheight)) p.append(Vector(0-dentchamfer,0,dentheight)) p.append(p[0]) p = Part.makePolygon(p) f = Part.Face(p) dentshape = f.extrude(Vector(0,dentwidth,0)) dentshape.rotate(Vector(0,0,0),Vector(0,0,1),dentrotation) if dentrotation == 0: dentshape.translate(Vector(length,dentoffset,0)) elif dentrotation == 90: dentshape.translate(Vector(length-dentoffset,width,0)) elif dentrotation == 180: dentshape.translate(Vector(0,width-dentoffset,0)) elif dentrotation == 270: dentshape.translate(Vector(dentoffset,0,0)) dentshape.translate(Vector(0,0,dentlevel)) shape = shape.fuse(dentshape) shape = self.processSubShapes(obj,shape,pl) self.applyShape(obj,shape,pl)
def execute(self,obj): if self.clone(obj): return pl = obj.Placement slabtype = obj.SlabType length = obj.Length.Value width = obj.Width.Value height = obj.Height.Value base = obj.SlabBase.Value holenumber = obj.HoleNumber holemajor = obj.HoleMajor.Value holeminor = obj.HoleMinor.Value holespacing = obj.HoleSpacing.Value slant = (height-base) / 3 # this gives the inclination of the vertical walls if (length == 0) or (width == 0) or (height == 0): return if base >= height: return if height < (base*2): return if (holenumber > 0) and ( (holespacing == 0) or (holemajor == 0) or (holeminor == 0) ): return if holemajor < holeminor: return import Part p = [] if slabtype == "Champagne": p.append(Vector(0,0,0)) p.append(Vector(0,slant,height-base)) p.append(Vector(0,0,height-base)) p.append(Vector(0,0,height)) p.append(Vector(0,width,height)) p.append(Vector(0,width,height-base)) p.append(Vector(0,width-slant,height-base)) p.append(Vector(0,width,0)) elif slabtype == "Hat": p.append(Vector(0,0,0)) p.append(Vector(0,0,base)) p.append(Vector(0,slant,base)) p.append(Vector(0,slant*2,height)) p.append(Vector(0,width-slant*2,height)) p.append(Vector(0,width-slant,base)) p.append(Vector(0,width,base)) p.append(Vector(0,width,0)) else: return None p.append(p[0]) p = Part.makePolygon(p) f = Part.Face(p) shape = f.extrude(Vector(length,0,0)) if holenumber > 0: holespan = holenumber * holeminor + (holenumber - 1) * holespacing holestart = (width/2 - holespan/2) + holeminor/2 if holeminor != holemajor: e = Part.Ellipse(Vector(0,0,0),Vector(0,holeminor/2,0),Vector(0,0,holemajor/2)).toShape() e.translate(Vector(0,0,-holemajor/2)) else: e = Part.Circle(Vector(0,0,0),Vector(1,0,0),holemajor/2).toShape() w = Part.Wire([e]) f = Part.Face(w) tube = f.extrude(Vector(length,0,0)) for i in range(holenumber): x = holestart + i*(holeminor+holespacing) s = tube.copy() s.translate(Vector(0,x,height/2)) shape = shape.cut(s) shape = self.processSubShapes(obj,shape,pl) self.applyShape(obj,shape,pl)
def isDrillable(obj, candidate, tooldiameter=None): """ Checks candidates to see if they can be drilled. Candidates can be either faces - circular or cylindrical or circular edges. The tooldiameter can be optionally passed. if passed, the check will return False for any holes smaller than the tooldiameter. obj=Shape candidate = Face or Edge tooldiameter=float """ PathLog.track('obj: {} candidate: {} tooldiameter {}'.format(obj, candidate, tooldiameter)) drillable = False if candidate.ShapeType == 'Face': face = candidate # eliminate flat faces if (round(face.ParameterRange[0], 8) == 0.0) and (round(face.ParameterRange[1], 8) == round(math.pi * 2, 8)): for edge in face.Edges: # Find seam edge and check if aligned to Z axis. if (isinstance(edge.Curve, Part.Line)): PathLog.debug("candidate is a circle") v0 = edge.Vertexes[0].Point v1 = edge.Vertexes[1].Point #check if the cylinder seam is vertically aligned. Eliminate tilted holes if (numpy.isclose(v1.sub(v0).x, 0, rtol=1e-05, atol=1e-06)) and \ (numpy.isclose(v1.sub(v0).y, 0, rtol=1e-05, atol=1e-06)): drillable = True # vector of top center lsp = Vector(face.BoundBox.Center.x, face.BoundBox.Center.y, face.BoundBox.ZMax) # vector of bottom center lep = Vector(face.BoundBox.Center.x, face.BoundBox.Center.y, face.BoundBox.ZMin) # check if the cylindrical 'lids' are inside the base # object. This eliminates extruded circles but allows # actual holes. if obj.isInside(lsp, 1e-6, False) or obj.isInside(lep, 1e-6, False): PathLog.track("inside check failed. lsp: {} lep: {}".format(lsp,lep)) drillable = False # eliminate elliptical holes elif not hasattr(face.Surface, "Radius"): PathLog.debug("candidate face has no radius attribute") drillable = False else: if tooldiameter is not None: drillable = face.Surface.Radius >= tooldiameter/2 else: drillable = True else: for edge in candidate.Edges: if isinstance(edge.Curve, Part.Circle) and edge.isClosed(): PathLog.debug("candidate is a circle or ellipse") if not hasattr(edge.Curve, "Radius"): PathLog.debug("No radius. Ellipse.") drillable = False else: PathLog.debug("Has Radius, Circle") if tooldiameter is not None: drillable = edge.Curve.Radius >= tooldiameter/2 if not drillable: FreeCAD.Console.PrintMessage( "Found a drillable hole with diameter: {}: " "too small for the current tool with " "diameter: {}".format(edge.Curve.Radius*2, tooldiameter)) else: drillable = True PathLog.debug("candidate is drillable: {}".format(drillable)) return drillable
def execute(self, obj): "constructs the shape of the stairs" if self.clone(obj): return import Part self.steps = [] self.pseudosteps = [] self.structures = [] pl = obj.Placement landings = 0 base = None if obj.Base: if hasattr(obj.Base, "Shape"): if obj.Base.Shape: if obj.Base.Shape.Solids: base = obj.Base.Shape.copy() # special case NumberOfSteps = 1 : multi-edges landing if (not base) and obj.Width.Value and obj.Height.Value and ( obj.NumberOfSteps > 0): if obj.Base: if not obj.Base.isDerivedFrom("Part::Feature"): return if obj.Base.Shape.Solids: obj.Shape = obj.Base.Shape.copy() obj.Placement = FreeCAD.Placement( obj.Base.Placement).multiply(pl) obj.TreadDepth = 0.0 obj.RiserHeight = 0.0 return if not obj.Base.Shape.Edges: return if obj.Base.Shape.Faces: return if (len(obj.Base.Shape.Edges) == 1): edge = obj.Base.Shape.Edges[0] if isinstance(edge.Curve, (Part.LineSegment, Part.Line)): # preparing for multi-edges landing / segment staircase if obj.NumberOfSteps > 1: if obj.Landings == "At center": landings = 1 self.makeStraightStairsWithLanding(obj, edge) else: self.makeStraightStairs(obj, edge) # preparing for multi-edges landing / segment staircase if obj.NumberOfSteps == 1: self.makeStraightLanding(obj, edge) if obj.NumberOfSteps == 0: pass # Should delete the whole shape else: if obj.Landings == "At center": landings = 1 self.makeCurvedStairsWithLandings(obj, edge) else: self.makeCurvedStairs(obj, edge) elif (len(obj.Base.Shape.Edges) >= 1): if obj.NumberOfSteps == 1: edges = obj.Base.Shape.Edges self.makeMultiEdgesLanding(obj, edges) else: if not obj.Length.Value: return edge = Part.LineSegment(Vector(0, 0, 0), Vector(obj.Length.Value, 0, 0)).toShape() if obj.Landings == "At center": landings = 1 self.makeStraightStairsWithLanding(obj, edge) else: self.makeStraightStairs(obj, edge) if self.structures or self.steps: base = Part.makeCompound(self.structures + self.steps) elif self.pseudosteps: shape = Part.makeCompound(self.pseudosteps) obj.Shape = shape obj.Placement = pl return base = self.processSubShapes(obj, base, pl) if base: if not base.isNull(): obj.Shape = base obj.Placement = pl # compute step data if obj.NumberOfSteps > 1: l = obj.Length.Value h = obj.Height.Value if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): l = obj.Base.Shape.Length if obj.Base.Shape.BoundBox.ZLength: h = obj.Base.Shape.BoundBox.ZLength if obj.LandingDepth: obj.TreadDepth = float(l - (landings * obj.LandingDepth.Value)) / ( obj.NumberOfSteps - (1 + landings)) else: obj.TreadDepth = float(l - (landings * obj.Width.Value)) / ( obj.NumberOfSteps - (1 + landings)) obj.RiserHeight = float(h) / obj.NumberOfSteps obj.BlondelRatio = obj.RiserHeight.Value * 2 + obj.TreadDepth.Value
def getLength(self): """Return the length of the line.""" p1 = Vector(self.coords.point.getValues()[0].getValue()) p2 = Vector(self.coords.point.getValues()[-1].getValue()) return (p2.sub(p1)).Length
def makeMultiEdgesLanding(self, obj, edges): "builds a 'multi-edges' landing from edges" # 'copying' from makeStraightLanding() import Part, DraftGeomUtils v, vLength, vWidth, vBase = [], [], [], [] p1o, p2o, p1, p2, p3, p4 = [], [], [], [], [], [] outline, outlineP1P2, outlineP3P4 = [], [], [] enum_edges = enumerate(edges) for i, edge in enum_edges: v.append(DraftGeomUtils.vec(edge)) vLength.append(Vector(v[i].x, v[i].y, 0)) # TODO obj.Width[i].Value for different 'edges' / 'sections' of the landing vWidth.append( DraftVecUtils.scaleTo(vLength[i].cross(Vector(0, 0, 1)), obj.Width.Value)) vBase.append(edges[i].Vertexes[0].Point) vBase[i] = self.vbaseFollowLastSement(obj, vBase[i]) # step + structure # assume all left-align first # no nosing p1o.append(vBase[i].add( Vector(0, 0, -abs(obj.TreadThickness.Value)))) p2o.append(p1o[i].add(vLength[i])) p1.append( self.align(vBase[i], obj.Align, vWidth[i]).add( Vector(0, 0, -abs(obj.TreadThickness.Value)))) p2.append(p1[i].add(vLength[i])) p3.append(p2[i].add(vWidth[i])) p4.append(p3[i].add(DraftVecUtils.neg(vLength[i]))) if obj.Align == 'Left': outlineP1P2.append(p1[i]) outlineP1P2.append( p2[i] ) # can better skip 1 'supposedly' overlapping point every pair? if i > 0: print("Debug - intersection calculation") print(p3[i - 1]) print(p4[i - 1]) print(p3[i]) print(p4[i]) intersection = DraftGeomUtils.findIntersection( p3[i - 1], p4[i - 1], p3[i], p4[i], True, True) print(intersection) outlineP3P4.insert(0, intersection[0]) else: outlineP3P4.insert(0, p4[i]) elif obj.Align == 'Right': if i > 0: intersection = DraftGeomUtils.findIntersection( p1[i - 1], p2[i - 1], p1[i], p2[i], True, True) outlineP1P2.append(intersection[0]) else: outlineP1P2.append(p1[i]) outlineP3P4.insert(0, p4[i]) outlineP3P4.insert(0, p3[i]) elif obj.Align == 'Center': if i > 0: intersection = DraftGeomUtils.findIntersection( p1[i - 1], p2[i - 1], p1[i], p2[i], True, True) outlineP1P2.append(intersection[0]) intersection = DraftGeomUtils.findIntersection( p3[i - 1], p4[i - 1], p3[i], p4[i], True, True) outlineP3P4.insert(0, intersection[0]) else: outlineP1P2.append(p1[i]) outlineP3P4.insert(0, p4[i]) else: outlineP1P2.append(p1[i]) outlineP1P2.append(p2[i]) outlineP3P4.insert(0, p4[i]) outlineP3P4.insert(0, p3[i]) # add back last/first 'missing' point(s) if obj.Align in ['Left', 'Center']: outlineP3P4.insert(0, p3[i]) if obj.Align in ['Right', 'Center']: outlineP1P2.append(p2[i]) outline = outlineP1P2 + outlineP3P4 outline.append(p1[0]) print(outlineP1P2) print(outlineP3P4) print(outline) stepFace = Part.Face(Part.makePolygon(outline)) if obj.TreadThickness.Value: step = stepFace.extrude(Vector(0, 0, abs(obj.TreadThickness.Value))) self.steps.append(step) else: self.pseudosteps.append(step) if obj.StructureThickness.Value: landingFace = stepFace struct = landingFace.extrude( Vector(0, 0, -abs(obj.StructureThickness.Value))) if struct: self.structures.append(struct) obj.AbsTop = vBase[1]
def p2(self): """Get the second point (on u axis) of the rectangle.""" return Vector(self.coords.point.getValues()[3].getValue())
def makeStraightLanding(self, obj, edge, numberofsteps=None, callByMakeStraightStairsWithLanding=False): "builds a landing from a straight edge" # general data if not numberofsteps: numberofsteps = obj.NumberOfSteps import Part, DraftGeomUtils v = DraftGeomUtils.vec(edge) vLength = Vector(v.x, v.y, 0) vWidth = vWidth = DraftVecUtils.scaleTo(vLength.cross(Vector(0, 0, 1)), obj.Width.Value) vBase = edge.Vertexes[0].Point # if not call by makeStraightStairsWithLanding() - not 're-base' in function there, then 're-base' here if not callByMakeStraightStairsWithLanding: vBase = self.vbaseFollowLastSement(obj, vBase) obj.AbsTop = vBase vNose = DraftVecUtils.scaleTo(vLength, -abs(obj.Nosing.Value)) h = obj.Height.Value l = obj.Length.Value if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): l = obj.Base.Shape.Length if obj.Base.Shape.BoundBox.ZLength: h = obj.Base.Shape.BoundBox.ZLength if obj.LandingDepth: fLength = float(l - obj.LandingDepth.Value) / (numberofsteps - 2) else: fLength = float(l - obj.Width.Value) / (numberofsteps - 2) fHeight = float(h) / numberofsteps a = math.atan(fHeight / fLength) print("landing data:", fLength, ":", fHeight) # step p1 = self.align(vBase, obj.Align, vWidth) p1o = p1.add(Vector(0, 0, -abs(obj.TreadThickness.Value))) p1 = p1.add(vNose).add(Vector(0, 0, -abs(obj.TreadThickness.Value))) p2 = p1.add(DraftVecUtils.neg(vNose)).add(vLength) p3 = p2.add(vWidth) p4 = p3.add(DraftVecUtils.neg(vLength)).add(vNose) p4o = p3.add(DraftVecUtils.neg(vLength)) if not callByMakeStraightStairsWithLanding: p2o = p2 p3o = p3 if obj.Flight == "HalfTurnLeft": p1 = p1.add(-vWidth) p2 = p2.add(-vWidth) step = Part.Face(Part.makePolygon([p1, p2, p3, p4, p1])) if obj.TreadThickness.Value: step = step.extrude(Vector(0, 0, abs(obj.TreadThickness.Value))) self.steps.append(step) else: self.pseudosteps.append(step) # structure lProfile = [] struct = None p7 = None p1 = p1.add(DraftVecUtils.neg(vNose)) p2 = p1.add(Vector(0, 0, -fHeight)).add( Vector(0, 0, -obj.StructureThickness.Value / math.cos(a))) resheight = p1.sub(p2).Length - obj.StructureThickness.Value reslength = resheight / math.tan(a) p3 = p2.add(DraftVecUtils.scaleTo(vLength, reslength)).add( Vector(0, 0, resheight)) p6 = p1.add(vLength) if obj.TreadThickness.Value: if obj.Flight == "Straight": p7 = p6.add(Vector(0, 0, obj.TreadThickness.Value)) reslength = fLength + ( obj.StructureThickness.Value / math.sin(a) - (fHeight - obj.TreadThickness.Value) / math.tan(a)) if p7: p5 = p7.add(DraftVecUtils.scaleTo(vLength, reslength)) else: if obj.Flight == "Straight": p5 = p6.add(DraftVecUtils.scaleTo(vLength, reslength)) else: p5 = None resheight = obj.StructureThickness.Value + obj.TreadThickness.Value reslength = resheight / math.tan(a) if obj.Flight == "Straight": p4 = p5.add(DraftVecUtils.scaleTo(vLength, -reslength)).add( Vector(0, 0, -resheight)) else: p4 = p6.add(Vector(0, 0, -obj.StructureThickness.Value)) if obj.Structure == "Massive": if obj.StructureThickness.Value: if p7: struct = Part.Face( Part.makePolygon([p1, p2, p3, p4, p5, p7, p6, p1])) elif p5: struct = Part.Face( Part.makePolygon([p1, p2, p3, p4, p5, p6, p1])) else: struct = Part.Face( Part.makePolygon([p1, p2, p3, p4, p6, p1])) evec = vWidth mvec = FreeCAD.Vector(0.0, 0) if obj.StructureOffset.Value: mvec = DraftVecUtils.scaleTo(vWidth, obj.StructureOffset.Value) struct.translate(mvec) if obj.Flight == "HalfTurnLeft": evec = DraftVecUtils.scaleTo( evec, 2 * evec.Length - 2 * mvec.Length) else: evec = DraftVecUtils.scaleTo( evec, evec.Length - (2 * mvec.Length)) struct = struct.extrude(evec) elif obj.Structure in ["One stringer", "Two stringers"]: if obj.StringerWidth.Value and obj.StructureThickness.Value: p1b = p1.add(Vector(0, 0, -fHeight)) reslength = fHeight / math.tan(a) p1c = p1.add(DraftVecUtils.scaleTo(vLength, reslength)) p5b = None p5c = None if obj.TreadThickness.Value: reslength = obj.StructureThickness.Value / math.sin(a) p5b = p5.add(DraftVecUtils.scaleTo(vLength, -reslength)) reslength = obj.TreadThickness.Value / math.tan(a) p5c = p5b.add(DraftVecUtils.scaleTo( vLength, -reslength)).add( Vector(0, 0, -obj.TreadThickness.Value)) pol = Part.Face( Part.makePolygon( [p1c, p1b, p2, p3, p4, p5, p5b, p5c, p1c])) else: pol = Part.Face( Part.makePolygon([p1c, p1b, p2, p3, p4, p5, p1c])) evec = DraftVecUtils.scaleTo(vWidth, obj.StringerWidth.Value) if obj.Structure == "One stringer": if obj.StructureOffset.Value: mvec = DraftVecUtils.scaleTo(vWidth, obj.StructureOffset.Value) else: mvec = DraftVecUtils.scaleTo( vWidth, (vWidth.Length / 2) - obj.StringerWidth.Value / 2) pol.translate(mvec) struct = pol.extrude(evec) elif obj.Structure == "Two stringers": pol2 = pol.copy() if obj.StructureOffset.Value: mvec = DraftVecUtils.scaleTo(vWidth, obj.StructureOffset.Value) pol.translate(mvec) mvec = vWidth.add(mvec.negative()) pol2.translate(mvec) else: pol2.translate(vWidth) s1 = pol.extrude(evec) s2 = pol2.extrude(evec.negative()) struct = Part.makeCompound([s1, s2]) # Overwriting result of above functions if case fit - should better avoid running the above in first place (better rewrite later) if not callByMakeStraightStairsWithLanding: if obj.StructureThickness.Value: struct = None landingFace = Part.Face( Part.makePolygon([p1o, p2o, p3o, p4o, p1o])) struct = landingFace.extrude( Vector(0, 0, -abs(obj.StructureThickness.Value))) if struct: self.structures.append(struct)
def p4(self): """Get the fourth point (on v axis) of the rectangle.""" return Vector(self.coords.point.getValues()[1].getValue())
def makeStraightStairs(self, obj, edge, numberofsteps=None): "builds a simple, straight staircase from a straight edge" # Upgrade obj if it is from an older version of FreeCAD if not (hasattr(obj, "StringerOverlap")): obj.addProperty( "App::PropertyLength", "StringerOverlap", "Structure", QT_TRANSLATE_NOOP( "App::Property", "The overlap of the stringers above the bottom of the treads" )) # general data import Part, DraftGeomUtils if not numberofsteps: numberofsteps = obj.NumberOfSteps # if not numberofsteps - not call by makeStraightStairsWithLanding() # if not 're-base' there (StraightStair is part of StraightStairsWithLanding 'flight'), then 're-base' here (StraightStair is individual 'flight') callByMakeStraightStairsWithLanding = False else: callByMakeStraightStairsWithLanding = True v = DraftGeomUtils.vec(edge) vLength = DraftVecUtils.scaleTo( v, float(edge.Length) / (numberofsteps - 1)) vLength = Vector(vLength.x, vLength.y, 0) if round(v.z, Draft.precision()) != 0: h = v.z else: h = obj.Height.Value vHeight = Vector(0, 0, float(h) / numberofsteps) vWidth = DraftVecUtils.scaleTo(vLength.cross(Vector(0, 0, 1)), obj.Width.Value) vBase = edge.Vertexes[0].Point if not callByMakeStraightStairsWithLanding: if obj.LastSegment: print("obj.LastSegment is: ") print(obj.LastSegment.Name) lastSegmentAbsTop = obj.LastSegment.AbsTop print("lastSegmentAbsTop is: ") print(lastSegmentAbsTop) vBase = Vector( vBase.x, vBase.y, lastSegmentAbsTop.z) # use Last Segment top's z-coordinate obj.AbsTop = vBase.add(Vector(0, 0, h)) vNose = DraftVecUtils.scaleTo(vLength, -abs(obj.Nosing.Value)) a = math.atan(vHeight.Length / vLength.Length) # steps for i in range(numberofsteps - 1): p1 = vBase.add((Vector(vLength).multiply(i)).add( Vector(vHeight).multiply(i + 1))) p1 = self.align(p1, obj.Align, vWidth) p1 = p1.add(vNose).add(Vector(0, 0, -abs(obj.TreadThickness.Value))) p2 = p1.add(DraftVecUtils.neg(vNose)).add(vLength) p3 = p2.add(vWidth) p4 = p3.add(DraftVecUtils.neg(vLength)).add(vNose) step = Part.Face(Part.makePolygon([p1, p2, p3, p4, p1])) if obj.TreadThickness.Value: step = step.extrude(Vector(0, 0, abs(obj.TreadThickness.Value))) self.steps.append(step) else: self.pseudosteps.append(step) # structure lProfile = [] struct = None if obj.Structure == "Massive": if obj.StructureThickness.Value: for i in range(numberofsteps - 1): if not lProfile: lProfile.append(vBase) last = lProfile[-1] if len(lProfile) == 1: last = last.add( Vector(0, 0, -abs(obj.TreadThickness.Value))) lProfile.append(last.add(vHeight)) lProfile.append(lProfile[-1].add(vLength)) resHeight1 = obj.StructureThickness.Value / math.cos(a) lProfile.append(lProfile[-1].add(Vector(0, 0, -resHeight1))) resHeight2 = ((numberofsteps - 1) * vHeight.Length) - ( resHeight1 + obj.TreadThickness.Value) resLength = (vLength.Length / vHeight.Length) * resHeight2 h = DraftVecUtils.scaleTo(vLength, -resLength) lProfile.append(lProfile[-1].add(Vector(h.x, h.y, -resHeight2))) lProfile.append(vBase) #print(lProfile) pol = Part.makePolygon(lProfile) struct = Part.Face(pol) evec = vWidth if obj.StructureOffset.Value: mvec = DraftVecUtils.scaleTo(vWidth, obj.StructureOffset.Value) struct.translate(mvec) evec = DraftVecUtils.scaleTo( evec, evec.Length - (2 * mvec.Length)) struct = struct.extrude(evec) elif obj.Structure in ["One stringer", "Two stringers"]: if obj.StringerWidth.Value and obj.StructureThickness.Value: hyp = math.sqrt(vHeight.Length**2 + vLength.Length**2) l1 = Vector(vLength).multiply(numberofsteps - 1) h1 = Vector(vHeight).multiply(numberofsteps - 1).add( Vector( 0, 0, -abs(obj.TreadThickness.Value) + obj.StringerOverlap.Value)) p1 = vBase.add(l1).add(h1) p1 = self.align(p1, obj.Align, vWidth) if obj.StringerOverlap.Value <= float(h) / numberofsteps: lProfile.append(p1) else: p1b = vBase.add(l1).add(Vector(0, 0, float(h))) p1a = p1b.add( Vector(vLength).multiply( (p1b.z - p1.z) / vHeight.Length)) lProfile.append(p1a) lProfile.append(p1b) h2 = (obj.StructureThickness.Value / vLength.Length) * hyp lProfile.append(p1.add(Vector(0, 0, -abs(h2)))) h3 = lProfile[-1].z - vBase.z l3 = (h3 / vHeight.Length) * vLength.Length v3 = DraftVecUtils.scaleTo(vLength, -l3) lProfile.append(lProfile[-1].add(Vector(0, 0, -abs(h3))).add(v3)) l4 = (obj.StructureThickness.Value / vHeight.Length) * hyp v4 = DraftVecUtils.scaleTo(vLength, -l4) lProfile.append(lProfile[-1].add(v4)) lProfile.append(lProfile[0]) #print(lProfile) pol = Part.makePolygon(lProfile) pol = Part.Face(pol) evec = DraftVecUtils.scaleTo(vWidth, obj.StringerWidth.Value) if obj.Structure == "One stringer": if obj.StructureOffset.Value: mvec = DraftVecUtils.scaleTo(vWidth, obj.StructureOffset.Value) else: mvec = DraftVecUtils.scaleTo( vWidth, (vWidth.Length / 2) - obj.StringerWidth.Value / 2) pol.translate(mvec) struct = pol.extrude(evec) elif obj.Structure == "Two stringers": pol2 = pol.copy() if obj.StructureOffset.Value: mvec = DraftVecUtils.scaleTo(vWidth, obj.StructureOffset.Value) pol.translate(mvec) mvec = vWidth.add(mvec.negative()) pol2.translate(mvec) else: pol2.translate(vWidth) s1 = pol.extrude(evec) s2 = pol2.extrude(evec.negative()) struct = Part.makeCompound([s1, s2]) if struct: self.structures.append(struct)
def get(self): """Get a vector from the point.""" p = self.coords.point.getValues()[0] return Vector(p[0], p[1], p[2])
def makeStraightStairsWithLanding(self, obj, edge): "builds a straight staircase with a landing in the middle" if obj.NumberOfSteps < 3: return import Part, DraftGeomUtils v = DraftGeomUtils.vec(edge) if obj.LandingDepth: reslength = edge.Length - obj.LandingDepth.Value else: reslength = edge.Length - obj.Width.Value vLength = DraftVecUtils.scaleTo( v, float(reslength) / (obj.NumberOfSteps - 2)) vLength = Vector(vLength.x, vLength.y, 0) vWidth = DraftVecUtils.scaleTo(vLength.cross(Vector(0, 0, 1)), obj.Width.Value) p1 = edge.Vertexes[0].Point if round(v.z, Draft.precision()) != 0: h = v.z else: h = obj.Height.Value hstep = h / obj.NumberOfSteps landing = int(obj.NumberOfSteps / 2) if obj.LastSegment: print("obj.LastSegment is: ") print(obj.LastSegment.Name) lastSegmentAbsTop = obj.LastSegment.AbsTop print("lastSegmentAbsTop is: ") print(lastSegmentAbsTop) p1 = Vector( p1.x, p1.y, lastSegmentAbsTop.z) # use Last Segment top's z-coordinate print(p1) obj.AbsTop = p1.add(Vector(0, 0, h)) p2 = p1.add( DraftVecUtils.scale(vLength, landing - 1).add(Vector(0, 0, landing * hstep))) if obj.LandingDepth: p3 = p2.add(DraftVecUtils.scaleTo(vLength, obj.LandingDepth.Value)) else: p3 = p2.add(DraftVecUtils.scaleTo(vLength, obj.Width.Value)) if obj.Flight == "HalfTurnLeft": p3r = p2 p4r = p2.add( DraftVecUtils.scale( -vLength, obj.NumberOfSteps - (landing + 1)).add( Vector(0, 0, (obj.NumberOfSteps - landing) * hstep))) else: p4 = p3.add( DraftVecUtils.scale( vLength, obj.NumberOfSteps - (landing + 1)).add( Vector(0, 0, (obj.NumberOfSteps - landing) * hstep))) self.makeStraightStairs(obj, Part.LineSegment(p1, p2).toShape(), landing) self.makeStraightLanding(obj, Part.LineSegment(p2, p3).toShape(), None, True) if obj.Flight == "HalfTurnLeft": self.makeStraightStairs(obj, Part.LineSegment(p3r, p4r).toShape(), obj.NumberOfSteps - landing) else: self.makeStraightStairs(obj, Part.LineSegment(p3, p4).toShape(), obj.NumberOfSteps - landing)
def getLocalCoords(self, point): """Return the coordinates of the given point, from the plane. If the `point` was constructed using the plane as origin, return the relative coordinates from the `point` to the plane. A vector is calculated from the plane's `position` to the external `point`, and this vector is projected onto each of the `u`, `v` and `axis` of the plane to determine the local, relative vector. Parameters ---------- point : Base::Vector3 The point external to the plane. Returns ------- Base::Vector3 The relative coordinates of the point from the plane. See Also -------- getGlobalCoords, getLocalRot, getGlobalRot Notes ----- The following graphic explains the coordinates. :: g GlobalCoords (1, 11) | | | (n) p point (1, 6) | LocalCoords (1, 1) | ----plane--------c-------- position (0, 5) In the graphic * `p` is an arbitrary point, external to the plane * `c` is the plane's `position` * `g` is the global coordinates of `p` when added to the plane * `n` is the relative coordinates of `p` when referred to the plane To do ----- Maybe a better name would be getRelativeCoords? """ pt = point.sub(self.position) xv = DraftVecUtils.project(pt, self.u) x = xv.Length # If the angle between the projection xv and u # is larger than 1 radian (57.29 degrees), use the negative # of the magnitude. Why exactly 1 radian? if xv.getAngle(self.u) > 1: x = -x yv = DraftVecUtils.project(pt, self.v) y = yv.Length if yv.getAngle(self.v) > 1: y = -y zv = DraftVecUtils.project(pt, self.axis) z = zv.Length if zv.getAngle(self.axis) > 1: z = -z return Vector(x, y, z)
def xy(point): """xy(point) Convenience function to return the projection of the Vector in the XY-plane.""" return Vector(point.x, point.y, 0)
def setup(doc=None, solvertype="ccxtools"): # init FreeCAD document if doc is None: doc = init_doc() # explanation object # just keep the following line and change text string in get_explanation method manager.add_explanation_obj( doc, get_explanation(manager.get_header(get_information()))) # geometric object # name is important because the other method in this module use obj name cube = doc.addObject("Part::Box", "Cube") cube.Height = "20 mm" cube.Length = "100 mm" cylinder = doc.addObject("Part::Cylinder", "Cylinder") cylinder.Height = "20 mm" cylinder.Radius = "6 mm" cylinder.Placement = FreeCAD.Placement( Vector(10, 12, 10), Rotation(0, 0, 90), Vector(0, 0, 0), ) cut = doc.addObject("Part::Cut", "Cut") cut.Base = cube cut.Tool = cylinder # mirroring mirror = doc.addObject("Part::Mirroring", "Mirror") mirror.Source = cut mirror.Normal = (1, 0, 0) mirror.Base = (100, 100, 20) # fusing fusion = doc.addObject("Part::Fuse", "Fusion") fusion.Base = cut fusion.Tool = mirror fusion.Refine = True # compound filter geom_obj = CompoundFilter.makeCompoundFilter(name='CompoundFilter') geom_obj.Base = fusion geom_obj.FilterType = 'window-volume' doc.recompute() if FreeCAD.GuiUp: geom_obj.Base.ViewObject.hide() geom_obj.ViewObject.Document.activeView().viewAxonometric() geom_obj.ViewObject.Document.activeView().fitAll() # analysis analysis = ObjectsFem.makeAnalysis(doc, "Analysis") # solver if solvertype == "calculix": solver_obj = ObjectsFem.makeSolverCalculix(doc, "SolverCalculiX") elif solvertype == "ccxtools": solver_obj = ObjectsFem.makeSolverCalculixCcxTools( doc, "CalculiXccxTools") solver_obj.WorkingDir = u"" else: FreeCAD.Console.PrintWarning( "Not known or not supported solver type: {}. " "No solver object was created.\n".format(solvertype)) if solvertype == "calculix" or solvertype == "ccxtools": solver_obj.SplitInputWriter = False solver_obj.AnalysisType = "static" solver_obj.GeometricalNonlinearity = "linear" solver_obj.ThermoMechSteadyState = False solver_obj.MatrixSolverType = "default" solver_obj.IterationsControlParameterTimeUse = False analysis.addObject(solver_obj) # material material_obj = ObjectsFem.makeMaterialSolid(doc, "FemMaterial") mat = material_obj.Material mat["Name"] = "CalculiX-Steel" mat["YoungsModulus"] = "210000 MPa" mat["PoissonRatio"] = "0.30" mat["Density"] = "7900 kg/m^3" mat["ThermalExpansionCoefficient"] = "0.012 mm/m/K" material_obj.Material = mat # constraint pressure con_pressure = ObjectsFem.makeConstraintPressure( doc, name="FemConstraintPressure") con_pressure.References = [(geom_obj, "Face8")] con_pressure.Pressure = 10.0 con_pressure.Reversed = False analysis.addObject(con_pressure) # constraint displacement con_disp = ObjectsFem.makeConstraintDisplacement( doc, name="FemConstraintDisplacment") con_disp.References = [(geom_obj, "Face4"), (geom_obj, "Face5")] con_disp.xFree = False con_disp.xFix = True analysis.addObject(con_disp) # constraints transform con_transform1 = ObjectsFem.makeConstraintTransform( doc, name="FemConstraintTransform1") con_transform1.References = [(geom_obj, "Face4")] con_transform1.TransformType = "Cylindrical" con_transform1.X_rot = 0.0 con_transform1.Y_rot = 0.0 con_transform1.Z_rot = 0.0 analysis.addObject(con_transform1) con_transform2 = ObjectsFem.makeConstraintTransform( doc, name="FemConstraintTransform2") con_transform2.References = [(geom_obj, "Face5")] con_transform2.TransformType = "Cylindrical" con_transform2.X_rot = 0.0 con_transform2.Y_rot = 0.0 con_transform2.Z_rot = 0.0 analysis.addObject(con_transform2) # mesh from .meshes.mesh_transform_beam_hinged_tetra10 import create_nodes, create_elements fem_mesh = Fem.FemMesh() control = create_nodes(fem_mesh) if not control: FreeCAD.Console.PrintError("Error on creating nodes.\n") control = create_elements(fem_mesh) if not control: FreeCAD.Console.PrintError("Error on creating elements.\n") femmesh_obj = analysis.addObject( ObjectsFem.makeMeshGmsh(doc, get_meshname()))[0] femmesh_obj.FemMesh = fem_mesh femmesh_obj.Part = geom_obj femmesh_obj.SecondOrderLinear = False femmesh_obj.CharacteristicLengthMax = '7 mm' doc.recompute() return doc
def edgeForCmd(cmd, startPoint): """edgeForCmd(cmd, startPoint). Returns an Edge representing the given command, assuming a given startPoint.""" PathLog.debug("cmd: {}".format(cmd)) PathLog.debug("startpoint {}".format(startPoint)) endPoint = commandEndPoint(cmd, startPoint) if (cmd.Name in CmdMoveStraight) or (cmd.Name in CmdMoveRapid): if pointsCoincide(startPoint, endPoint): return None return Part.Edge(Part.LineSegment(startPoint, endPoint)) if cmd.Name in CmdMoveArc: center = startPoint + commandEndPoint(cmd, Vector(0,0,0), 'I', 'J', 'K') A = xy(startPoint - center) B = xy(endPoint - center) d = -B.x * A.y + B.y * A.x if isRoughly(d, 0, 0.005): PathLog.debug("Half circle arc at: (%.2f, %.2f, %.2f)" % (center.x, center.y, center.z)) # we're dealing with half a circle here angle = getAngle(A) + math.pi/2 if cmd.Name in CmdMoveCW: angle -= math.pi else: C = A + B angle = getAngle(C) PathLog.debug("Arc (%8f) at: (%.2f, %.2f, %.2f) -> angle=%f" % (d, center.x, center.y, center.z, angle / math.pi)) R = A.Length PathLog.debug("arc: p1=(%.2f, %.2f) p2=(%.2f, %.2f) -> center=(%.2f, %.2f)" % (startPoint.x, startPoint.y, endPoint.x, endPoint.y, center.x, center.y)) PathLog.debug("arc: A=(%.2f, %.2f) B=(%.2f, %.2f) -> d=%.2f" % (A.x, A.y, B.x, B.y, d)) PathLog.debug("arc: R=%.2f angle=%.2f" % (R, angle/math.pi)) if isRoughly(startPoint.z, endPoint.z): midPoint = center + Vector(math.cos(angle), math.sin(angle), 0) * R PathLog.debug("arc: (%.2f, %.2f) -> (%.2f, %.2f) -> (%.2f, %.2f)" % (startPoint.x, startPoint.y, midPoint.x, midPoint.y, endPoint.x, endPoint.y)) PathLog.debug("StartPoint:{}".format(startPoint)) PathLog.debug("MidPoint:{}".format(midPoint)) PathLog.debug("EndPoint:{}".format(endPoint)) return Part.Edge(Part.Arc(startPoint, midPoint, endPoint)) # It's a Helix #print('angle: A=%.2f B=%.2f' % (getAngle(A)/math.pi, getAngle(B)/math.pi)) if cmd.Name in CmdMoveCW: cw = True else: cw = False angle = diffAngle(getAngle(A), getAngle(B), 'CW' if cw else 'CCW') height = endPoint.z - startPoint.z pitch = height * math.fabs(2 * math.pi / angle) if angle > 0: cw = not cw #print("Helix: R=%.2f h=%.2f angle=%.2f pitch=%.2f" % (R, height, angle/math.pi, pitch)) helix = Part.makeHelix(pitch, height, R, 0, not cw) helix.rotate(Vector(), Vector(0,0,1), 180 * getAngle(A) / math.pi) e = helix.Edges[0] helix.translate(startPoint - e.valueAt(e.FirstParameter)) return helix.Edges[0] return None
def execute(self,obj): "builds the wall shape" if self.clone(obj): return import Part, DraftGeomUtils pl = obj.Placement normal,length,width,height = self.getDefaultValues(obj) base = None face = None if obj.Base: # computing a shape from a base object if obj.Base.isDerivedFrom("Part::Feature"): if obj.Base.Shape.isNull(): return if not obj.Base.Shape.isValid(): if not obj.Base.Shape.Solids: # let pass invalid objects if they have solids... return if hasattr(obj,"Face"): if obj.Face > 0: if len(obj.Base.Shape.Faces) >= obj.Face: face = obj.Base.Shape.Faces[obj.Face-1] if face: # case 1: this wall is based on a specific face of its base object normal = face.normalAt(0,0) if normal.getAngle(Vector(0,0,1)) > math.pi/4: normal.multiply(width) base = face.extrude(normal) if obj.Align == "Center": base.translate(normal.negative().multiply(0.5)) elif obj.Align == "Right": base.translate(normal.negative()) else: normal.multiply(height) base = face.extrude(normal) elif obj.Base.Shape.Solids: # case 2: the base is already a solid base = obj.Base.Shape.copy() elif obj.Base.Shape.Edges: # case 3: the base is flat, we need to extrude it if not obj.Base.Shape.Faces: # set the length property if hasattr(obj.Base.Shape,"Length"): l = obj.Base.Shape.Length if obj.Length != l: obj.Length = l profiles = self.getProfiles(obj) if profiles: normal.multiply(height) base = profiles.pop() base.fix(0.1,0,1) base = base.extrude(normal) for p in profiles: p.fix(0.1,0,1) p = p.extrude(normal) base = base.fuse(p) else: base = None else: base = None FreeCAD.Console.PrintError(str(translate("Arch","Error: Invalid base object"))) elif obj.Base.isDerivedFrom("Mesh::Feature"): if obj.Base.Mesh.isSolid(): if obj.Base.Mesh.countComponents() == 1: sh = ArchCommands.getShapeFromMesh(obj.Base.Mesh) if sh.isClosed() and sh.isValid() and sh.Solids and (not sh.isNull()): base = sh else: FreeCAD.Console.PrintWarning(str(translate("Arch","This mesh is an invalid solid"))) obj.Base.ViewObject.show() else: # computing a shape from scratch if length and width and height: base = Part.makeBox(length,width,height) base = self.processSubShapes(obj,base,pl) self.applyShape(obj,base,pl)
def execute(self,obj): if self.clone(obj): return pl = obj.Placement length = obj.Length.Value width = obj.Width.Value height = obj.Height.Value chamfer = obj.Chamfer.Value groovedepth = obj.GrooveDepth.Value grooveheight = obj.GrooveHeight.Value spacing = obj.GrooveSpacing.Value number = obj.GrooveNumber dents = obj.Dents if (length == 0) or (width == 0) or (height == 0): return if (chamfer >= width/2) or (chamfer >= length/2): return import Part p = [] if chamfer > 0: p.append(Vector(chamfer,0,0)) p.append(Vector(length-chamfer,0,0)) p.append(Vector(length,chamfer,0)) p.append(Vector(length,width-chamfer,0)) p.append(Vector(length-chamfer,width,0)) p.append(Vector(chamfer,width,0)) p.append(Vector(0,width-chamfer,0)) p.append(Vector(0,chamfer,0)) else: p.append(Vector(0,0,0)) p.append(Vector(length,0,0)) p.append(Vector(length,width,0)) p.append(Vector(0,width,0)) p.append(p[0]) p = Part.makePolygon(p) f = Part.Face(p) shape = f.extrude(Vector(0,0,height)) if (groovedepth > 0) and (grooveheight > 0) and (spacing > 0) and (number > 0) and (groovedepth < length/2) and (groovedepth < width/2): p1 = [] p1.append(Vector(0,0,0)) p1.append(Vector(length,0,0)) p1.append(Vector(length,width,0)) p1.append(Vector(0,width,0)) p1.append(p1[0]) p1 = Part.makePolygon(p1) f1 = Part.Face(p1) groove = f1.extrude(Vector(0,0,grooveheight)) p2 = [] p2.append(Vector(groovedepth,groovedepth,0)) p2.append(Vector(length-groovedepth,groovedepth,0)) p2.append(Vector(length-groovedepth,width-groovedepth,0)) p2.append(Vector(groovedepth,width-groovedepth,0)) p2.append(p2[0]) p2 = Part.makePolygon(p2) f2 = Part.Face(p2) s = f2.extrude(Vector(0,0,grooveheight)) groove = groove.cut(s) for i in range(number): g = groove.copy() g.translate(Vector(0,0,spacing + i*(spacing+grooveheight))) shape = shape.cut(g) for dent in dents: dent = dent.split(";") if len(dent) == 7: dentlength = float(dent[0]) dentwidth = float(dent[1]) dentheight = float(dent[2]) dentslant = float(dent[3]) dentchamfer = chamfer dentlevel = float(dent[4]) dentrotation = float(dent[5]) dentoffset = float(dent[6]) if (dentlength == 0) or (dentwidth == 0) or (dentheight == 0): continue if dentslant >= dentheight: continue p = [] p.append(Vector(0-dentchamfer,0,0)) p.append(Vector(dentlength,0,dentslant)) p.append(Vector(dentlength,0,dentheight)) p.append(Vector(0-dentchamfer,0,dentheight)) p.append(p[0]) p = Part.makePolygon(p) f = Part.Face(p) dentshape = f.extrude(Vector(0,dentwidth,0)) dentshape.rotate(Vector(0,0,0),Vector(0,0,1),dentrotation) if dentrotation == 0: dentshape.translate(Vector(length,dentoffset,0)) elif dentrotation == 90: dentshape.translate(Vector(length-dentoffset,width,0)) elif dentrotation == 180: dentshape.translate(Vector(0,width-dentoffset,0)) elif dentrotation == 270: dentshape.translate(Vector(dentoffset,0,0)) dentshape.translate(Vector(0,0,dentlevel)) shape = shape.fuse(dentshape) shape = self.processSubShapes(obj,shape,pl) self.applyShape(obj,shape,pl)