| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | """Provides functions to create Sketch objects from Draft objects.""" |
| | |
| | |
| | |
| |
|
| | |
| | |
| | import math |
| |
|
| | import FreeCAD as App |
| | import DraftVecUtils |
| | import DraftGeomUtils |
| | from draftutils import gui_utils |
| | from draftutils import utils |
| | from draftutils.translate import translate |
| |
|
| |
|
| | def make_sketch( |
| | objects_list, |
| | autoconstraints=False, |
| | addTo=None, |
| | delete=False, |
| | name="Sketch", |
| | radiusPrecision=-1, |
| | tol=1e-3, |
| | ): |
| | """make_sketch(objects_list, [autoconstraints], [addTo], [delete], |
| | [name], [radiusPrecision], [tol]) |
| | |
| | Makes a Sketch objects_list with the given Draft objects. |
| | |
| | Parameters |
| | ---------- |
| | objects_list: can be single or list of objects of Draft type objects, |
| | Part::Feature, Part.Shape, or mix of them. |
| | |
| | autoconstraints(False): if True, coincident, horizontal and vertical |
| | constraints will be added automatically. |
| | |
| | addTo(None): if set to an existing sketch, geometry will be added to it |
| | instead of creating a new one. |
| | |
| | delete(False): if True, the original object will be deleted. |
| | If set to a string "all" the object and all its linked object will be |
| | deleted. |
| | |
| | name("Sketch"): the name for the new sketch object. |
| | |
| | radiusPrecision(-1): If <0, disable radius constraint. If =0, add individual |
| | radius constraint. If >0, the radius will be rounded according to this |
| | precision, and "Equal" constraint will be added to curve with equal |
| | radius within precision. |
| | |
| | tol(1e-3): Tolerance used to check if the shapes are planar and coplanar. |
| | Consider change to tol=-1 for a more accurate analysis. |
| | """ |
| |
|
| | if not App.ActiveDocument: |
| | App.Console.PrintError("No active document. Aborting\n") |
| | return |
| |
|
| | import Part |
| | from Sketcher import Constraint |
| |
|
| | |
| | shape_norm_yes = list() |
| | shape_norm_no = list() |
| |
|
| | if not isinstance(objects_list, (list, tuple)): |
| | objects_list = [objects_list] |
| |
|
| | for obj in objects_list: |
| | if isinstance(obj, Part.Shape): |
| | shape = obj |
| | elif not hasattr(obj, "Shape"): |
| | App.Console.PrintError(translate("draft", "No shape found") + "\n") |
| | return None |
| | else: |
| | shape = obj.Shape |
| |
|
| | if not DraftGeomUtils.is_planar(shape, tol): |
| | App.Console.PrintError(translate("draft", "All shapes must be planar") + "\n") |
| | return None |
| |
|
| | if DraftGeomUtils.get_normal(shape, tol): |
| | shape_norm_yes.append(shape) |
| | else: |
| | shape_norm_no.append(shape) |
| |
|
| | shapes_list = shape_norm_yes + shape_norm_no |
| |
|
| | |
| | if len(shape_norm_yes) >= 1: |
| | for shape in shapes_list[1:]: |
| | if not DraftGeomUtils.are_coplanar(shapes_list[0], shape, tol): |
| | App.Console.PrintError(translate("draft", "All shapes must be coplanar") + "\n") |
| | return None |
| | |
| | normal = DraftGeomUtils.get_normal(shapes_list[0], tol) |
| |
|
| | else: |
| | |
| | points = [vertex.Point for shape in shapes_list for vertex in shape.Vertexes] |
| | if len(points) >= 2: |
| | try: |
| | poly = Part.makePolygon(points) |
| | except Part.OCCError: |
| | |
| | normal = App.Vector(0, 0, 1) |
| | else: |
| | if not DraftGeomUtils.is_planar(poly, tol): |
| | App.Console.PrintError(translate("draft", "All shapes must be coplanar") + "\n") |
| | return None |
| | normal = DraftGeomUtils.get_shape_normal(poly) |
| | else: |
| | |
| | normal = App.Vector(0, 0, 1) |
| |
|
| | if addTo: |
| | nobj = addTo |
| | else: |
| | nobj = App.ActiveDocument.addObject("Sketcher::SketchObject", name) |
| |
|
| | |
| | constraints = [] |
| | radiuses = {} |
| |
|
| | def addRadiusConstraint(edge): |
| | try: |
| | if radiusPrecision < 0: |
| | return |
| | if radiusPrecision == 0: |
| | constraints.append(Constraint("Radius", nobj.GeometryCount - 1, edge.Curve.Radius)) |
| | return |
| | r = round(edge.Curve.Radius, radiusPrecision) |
| | constraints.append(Constraint("Equal", radiuses[r], nobj.GeometryCount - 1)) |
| | except KeyError: |
| | radiuses[r] = nobj.GeometryCount - 1 |
| | constraints.append(Constraint("Radius", nobj.GeometryCount - 1, r)) |
| | except AttributeError: |
| | pass |
| |
|
| | def convertBezier(edge): |
| | if DraftGeomUtils.geomType(edge) == "BezierCurve": |
| | return edge.Curve.toBSpline(edge.FirstParameter, edge.LastParameter).toShape() |
| | else: |
| | return edge |
| |
|
| | axis = App.Vector(0, 0, 1).cross(normal) |
| | if axis.Length > 1e-6: |
| | axis.normalize() |
| | elif normal.z >= 0: |
| | axis = App.Vector(0, 0, 1) |
| | else: |
| | axis = App.Vector(0, 0, -1) |
| | angle = math.degrees(DraftVecUtils.angle(normal, App.Vector(0, 0, 1))) |
| | rotation = App.Rotation(axis, angle) |
| |
|
| | point = shapes_list[0].Vertexes[0].Point |
| | base = App.Vector(normal) |
| | base.Length = point.dot( |
| | base.normalize() |
| | ) |
| |
|
| | nobj.Placement = App.Placement(base, rotation) |
| |
|
| | for obj in objects_list: |
| | ok = False |
| | tp = utils.get_type(obj) |
| |
|
| | if tp == "Point": |
| | |
| | |
| | |
| | shape = Part.Vertex(obj.Shape.Point) |
| | if angle: |
| | shape.rotate(App.Vector(0, 0, 0), axis, -angle) |
| | point = Part.Point(shape.Point) |
| | nobj.addGeometry(point) |
| | ok = True |
| |
|
| | elif tp == "Shape" or hasattr(obj, "Shape"): |
| | shape = obj if tp == "Shape" else obj.Shape |
| | for e in shape.Edges: |
| | newedge = convertBezier(e) |
| | nobj.addGeometry(DraftGeomUtils.orientEdge(newedge, normal, make_arc=True)) |
| | addRadiusConstraint(newedge) |
| | ok = True |
| |
|
| | if ok and delete: |
| |
|
| | def delObj(obj): |
| | if obj.InList: |
| | App.Console.PrintWarning( |
| | translate( |
| | "draft", "Cannot delete object {} with dependency".format(obj.Label) |
| | ) |
| | + "\n" |
| | ) |
| | else: |
| | obj.Document.removeObject(obj.Name) |
| |
|
| | try: |
| | if delete == "all": |
| | objs = [obj] |
| | while objs: |
| | obj = objs[0] |
| | objs = objs[1:] + obj.OutList |
| | delObj(obj) |
| | else: |
| | delObj(obj) |
| | except Exception as ex: |
| | App.Console.PrintWarning( |
| | translate("draft", "Failed to delete object {}: {}".format(obj.Label, ex)) |
| | + "\n" |
| | ) |
| |
|
| | nobj.addConstraint(constraints) |
| | if autoconstraints: |
| | nobj.detectMissingPointOnPointConstraints(utils.tolerance()) |
| | nobj.makeMissingPointOnPointCoincident(False) |
| | nobj.detectMissingVerticalHorizontalConstraints(utils.tolerance()) |
| | nobj.makeMissingVerticalHorizontal(False) |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | nobj.solve() |
| | for idx in nobj.RedundantConstraints[::-1]: |
| | |
| | nobj.delConstraint(idx - 1) |
| |
|
| | return nobj |
| |
|
| |
|
| | makeSketch = make_sketch |
| |
|
| | |
| |
|