| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | """Provides functions to create offsets of different shapes.""" |
| | |
| | |
| | |
| |
|
| | |
| | |
| | import math |
| |
|
| | import FreeCAD as App |
| | import DraftVecUtils |
| | from draftutils import gui_utils |
| | from draftutils import params |
| | from draftutils import utils |
| |
|
| | from draftmake.make_rectangle import make_rectangle |
| | from draftmake.make_wire import make_wire |
| | from draftmake.make_polygon import make_polygon |
| | from draftmake.make_circle import make_circle |
| | from draftmake.make_bspline import make_bspline |
| |
|
| |
|
| | def offset(obj, delta, copy=False, bind=False, sym=False, occ=False): |
| | """offset(object,delta,[copymode],[bind]) |
| | |
| | Offset the given wire by applying the given delta Vector to its first |
| | vertex. |
| | |
| | Parameters |
| | ---------- |
| | obj : |
| | |
| | delta : Base.Vector or list of Base.Vector |
| | If offsetting a BSpline, the delta must not be a Vector but a list |
| | of Vectors, one for each node of the spline. |
| | |
| | copy : bool |
| | If copymode is True, another object is created, otherwise the same |
| | object gets offsetted. |
| | |
| | copy : bool |
| | If bind is True, and provided the wire is open, the original |
| | and the offset wires will be bound by their endpoints, forming a face. |
| | |
| | sym : bool |
| | if sym is True, bind must be true too, and the offset is made on both |
| | sides, the total width being the given delta length. |
| | """ |
| | import Part |
| | import DraftGeomUtils |
| |
|
| | newwire = None |
| | delete = None |
| |
|
| | if copy is False and ( |
| | utils.get_type(obj).startswith("Sketcher::") |
| | or utils.get_type(obj).startswith("Part::") |
| | or utils.get_type(obj).startswith("PartDesign::") |
| | ): |
| | print( |
| | "the offset tool is currently unable to offset a non-Draft object directly - Creating a copy" |
| | ) |
| | copy = True |
| |
|
| | def getRect(p, obj): |
| | """returns length,height,placement""" |
| | pl = obj.Placement.copy() |
| | pl.Base = p[0] |
| | diag = p[2].sub(p[0]) |
| | bb = p[1].sub(p[0]) |
| | bh = p[3].sub(p[0]) |
| | nb = DraftVecUtils.project(diag, bb) |
| | nh = DraftVecUtils.project(diag, bh) |
| | if obj.Length.Value < 0: |
| | l = -nb.Length |
| | else: |
| | l = nb.Length |
| | if obj.Height.Value < 0: |
| | h = -nh.Length |
| | else: |
| | h = nh.Length |
| | return l, h, pl |
| |
|
| | def getRadius(obj, delta): |
| | """returns a new radius for a regular polygon""" |
| | an = math.pi / obj.FacesNumber |
| | nr = DraftVecUtils.rotate(delta, -an) |
| | nr.multiply(1 / math.cos(an)) |
| | nr = obj.Shape.Vertexes[0].Point.add(nr) |
| | nr = nr.sub(obj.Placement.Base) |
| | nr = nr.Length |
| | if obj.DrawMode == "inscribed": |
| | return nr |
| | else: |
| | return nr * math.cos(math.pi / obj.FacesNumber) |
| |
|
| | newwire = None |
| | if utils.get_type(obj) == "Circle": |
| | pass |
| | elif utils.get_type(obj) == "BSpline": |
| | pass |
| | else: |
| | if sym: |
| | d1 = App.Vector(delta).multiply(0.5) |
| | d2 = d1.negative() |
| | n1 = DraftGeomUtils.offsetWire(obj.Shape, d1) |
| | n2 = DraftGeomUtils.offsetWire(obj.Shape, d2) |
| | else: |
| | if isinstance(delta, float) and (len(obj.Shape.Edges) == 1): |
| | |
| | c = obj.Shape.Edges[0].Curve |
| | nc = Part.Circle(c.Center, c.Axis, delta) |
| | if len(obj.Shape.Vertexes) > 1: |
| | nc = Part.ArcOfCircle( |
| | nc, obj.Shape.Edges[0].FirstParameter, obj.Shape.Edges[0].LastParameter |
| | ) |
| | newwire = Part.Wire(nc.toShape()) |
| | p = [] |
| | else: |
| | newwire = DraftGeomUtils.offsetWire(obj.Shape, delta) |
| | if DraftGeomUtils.hasCurves(newwire) and copy: |
| | p = [] |
| | else: |
| | p = DraftGeomUtils.getVerts(newwire) |
| | if occ: |
| | newobj = App.ActiveDocument.addObject("Part::Feature", "Offset") |
| | newobj.Shape = DraftGeomUtils.offsetWire(obj.Shape, delta, occ=True) |
| | gui_utils.formatObject(newobj, obj) |
| | if not copy: |
| | delete = obj.Name |
| | elif bind: |
| | if not DraftGeomUtils.isReallyClosed(obj.Shape): |
| | if sym: |
| | s1 = n1 |
| | s2 = n2 |
| | else: |
| | s1 = obj.Shape |
| | s2 = newwire |
| | if s1 and s2: |
| | w1 = s1.Edges |
| | w2 = s2.Edges |
| | w3 = Part.LineSegment(s1.Vertexes[0].Point, s2.Vertexes[0].Point).toShape() |
| | w4 = Part.LineSegment(s1.Vertexes[-1].Point, s2.Vertexes[-1].Point).toShape() |
| | newobj = App.ActiveDocument.addObject("Part::Feature", "Offset") |
| | newobj.Shape = Part.Face(Part.Wire(w1 + [w3] + w2 + [w4])) |
| | else: |
| | print("Draft.offset: Unable to bind wires") |
| | else: |
| | newobj = App.ActiveDocument.addObject("Part::Feature", "Offset") |
| | newobj.Shape = Part.Face(obj.Shape.Wires[0]) |
| | if not copy: |
| | delete = obj.Name |
| | elif copy: |
| | newobj = None |
| | if sym: |
| | return None |
| | if utils.get_type(obj) == "Wire": |
| | if p: |
| | newobj = make_wire(p) |
| | newobj.Closed = obj.Closed |
| | elif newwire: |
| | newobj = App.ActiveDocument.addObject("Part::Feature", "Offset") |
| | newobj.Shape = newwire |
| | else: |
| | print("Draft.offset: Unable to duplicate this object") |
| | elif utils.get_type(obj) == "Rectangle": |
| | if p: |
| | length, height, plac = getRect(p, obj) |
| | newobj = make_rectangle(length, height, plac) |
| | elif newwire: |
| | newobj = App.ActiveDocument.addObject("Part::Feature", "Offset") |
| | newobj.Shape = newwire |
| | else: |
| | print("Draft.offset: Unable to duplicate this object") |
| | elif utils.get_type(obj) == "Circle": |
| | pl = obj.Placement |
| | newobj = make_circle(delta) |
| | newobj.FirstAngle = obj.FirstAngle |
| | newobj.LastAngle = obj.LastAngle |
| | newobj.Placement = pl |
| | elif utils.get_type(obj) == "Polygon": |
| | pl = obj.Placement |
| | newobj = make_polygon(obj.FacesNumber) |
| | newobj.Radius = getRadius(obj, delta) |
| | newobj.DrawMode = obj.DrawMode |
| | newobj.Placement = pl |
| | elif utils.get_type(obj) == "BSpline": |
| | newobj = make_bspline(delta) |
| | newobj.Closed = obj.Closed |
| | else: |
| | |
| | try: |
| | if p: |
| | newobj = make_wire(p) |
| | newobj.Closed = DraftGeomUtils.isReallyClosed(obj.Shape) |
| | except Part.OCCError: |
| | pass |
| | if (not newobj) and newwire: |
| | newobj = App.ActiveDocument.addObject("Part::Feature", "Offset") |
| | newobj.Shape = newwire |
| | if not newobj: |
| | print("Draft.offset: Unable to create an offset") |
| | if newobj: |
| | gui_utils.formatObject(newobj, obj) |
| | else: |
| | newobj = None |
| | if sym: |
| | return None |
| | if utils.get_type(obj) == "Wire": |
| | if obj.Base or obj.Tool: |
| | App.Console.PrintWarning("Warning: object history removed\n") |
| | obj.Base = None |
| | obj.Tool = None |
| | obj.Placement = App.Placement() |
| | obj.Points = p |
| | elif utils.get_type(obj) == "BSpline": |
| | |
| | obj.Points = delta |
| | |
| | elif utils.get_type(obj) == "Rectangle": |
| | length, height, plac = getRect(p, obj) |
| | obj.Placement = plac |
| | obj.Length = length |
| | obj.Height = height |
| | elif utils.get_type(obj) == "Circle": |
| | obj.Radius = delta |
| | elif utils.get_type(obj) == "Polygon": |
| | obj.Radius = getRadius(obj, delta) |
| | elif utils.get_type(obj) == "Part": |
| | print("unsupported object") |
| | newobj = obj |
| | if copy and params.get_param("selectBaseObjects"): |
| | gui_utils.select(obj) |
| | else: |
| | gui_utils.select(newobj) |
| | if delete: |
| | App.ActiveDocument.removeObject(delete) |
| | return newobj |
| |
|
| |
|
| | |
| |
|