23
"""Provides functions to create Sketch objects from Draft objects."""
35
import draftutils.utils as utils
36
import draftutils.gui_utils as gui_utils
38
from draftutils.translate import translate
41
def make_sketch(objects_list, autoconstraints=False, addTo=None,
42
delete=False, name="Sketch", radiusPrecision=-1, tol=1e-3):
43
"""make_sketch(objects_list, [autoconstraints], [addTo], [delete],
44
[name], [radiusPrecision], [tol])
46
Makes a Sketch objects_list with the given Draft objects.
50
objects_list: can be single or list of objects of Draft type objects,
51
Part::Feature, Part.Shape, or mix of them.
53
autoconstraints(False): if True, constraints will be automatically added to
54
wire nodes, rectangles and circles.
56
addTo(None) : if set to an existing sketch, geometry will be added to it
57
instead of creating a new one.
59
delete(False): if True, the original object will be deleted.
60
If set to a string 'all' the object and all its linked object will be
63
name('Sketch'): the name for the new sketch object.
65
radiusPrecision(-1): If <0, disable radius constraint. If =0, add individual
66
radius constraint. If >0, the radius will be rounded according to this
67
precision, and 'Equal' constraint will be added to curve with equal
68
radius within precision.
70
tol(1e-3): Tolerance used to check if the shapes are planar and coplanar.
71
Consider change to tol=-1 for a more accurate analysis.
74
if not App.ActiveDocument:
75
App.Console.PrintError("No active document. Aborting\n")
79
from Sketcher import Constraint
87
v_dir = gui_utils.get_3d_view().getViewDirection()
89
v_dir = App.Base.Vector(0,0,-1)
92
shape_norm_yes = list()
93
shape_norm_no = list()
95
if not isinstance(objects_list,(list,tuple)):
96
objects_list = [objects_list]
98
for obj in objects_list:
99
if isinstance(obj,Part.Shape):
101
elif not hasattr(obj,'Shape'):
102
App.Console.PrintError(translate("draft",
103
"No shape found")+"\n")
108
if not DraftGeomUtils.is_planar(shape, tol):
109
App.Console.PrintError(translate("draft",
110
"All Shapes must be planar")+"\n")
113
if DraftGeomUtils.get_normal(shape, tol):
114
shape_norm_yes.append(shape)
116
shape_norm_no.append(shape)
119
shapes_list = shape_norm_yes + shape_norm_no
122
if len(shape_norm_yes) >= 1:
123
for shape in shapes_list[1:]:
124
if not DraftGeomUtils.are_coplanar(shapes_list[0], shape, tol):
125
App.Console.PrintError(translate("draft",
126
"All Shapes must be coplanar")+"\n")
129
normal = DraftGeomUtils.get_normal(shapes_list[0], tol)
133
points = [vertex.Point for shape in shapes_list for vertex in shape.Vertexes]
135
poly = Part.makePolygon(points)
136
if not DraftGeomUtils.is_planar(poly, tol):
137
App.Console.PrintError(translate("draft",
138
"All Shapes must be coplanar")+"\n")
140
normal = DraftGeomUtils.get_normal(poly, tol)
143
poly_dir = poly.Edges[0].Curve.Direction
144
normal = (v_dir - v_dir.dot(poly_dir)*poly_dir).normalize()
145
normal = normal.negative()
148
normal = v_dir.negative()
154
nobj = App.ActiveDocument.addObject("Sketcher::SketchObject", name)
160
def addRadiusConstraint(edge):
162
if radiusPrecision<0:
164
if radiusPrecision==0:
165
constraints.append(Constraint('Radius',
166
nobj.GeometryCount-1, edge.Curve.Radius))
168
r = round(edge.Curve.Radius,radiusPrecision)
169
constraints.append(Constraint('Equal',
170
radiuses[r],nobj.GeometryCount-1))
172
radiuses[r] = nobj.GeometryCount-1
173
constraints.append(Constraint('Radius',nobj.GeometryCount-1, r))
174
except AttributeError:
177
def convertBezier(edge):
178
if DraftGeomUtils.geomType(edge) == "BezierCurve":
179
return(edge.Curve.toBSpline(edge.FirstParameter,edge.LastParameter).toShape())
184
axis = App.Vector(0, 0, 1).cross(normal)
185
angle = DraftVecUtils.angle(normal, App.Vector(0, 0, 1)) * App.Units.Radian
186
rotation = App.Rotation(axis, angle)
188
point = shapes_list[0].Vertexes[0].Point
189
base = App.Vector(normal)
190
base.Length = point.dot(base.normalize())
192
nobj.Placement = App.Placement(base, rotation)
194
for obj in objects_list:
196
tp = utils.get_type(obj)
198
if tp in ["Circle","Ellipse"]:
200
edge = obj.Shape.Edges[0]
201
if len(edge.Vertexes) == 1:
202
newedge = DraftGeomUtils.orientEdge(edge, normal)
203
nobj.addGeometry(newedge)
206
circle = DraftGeomUtils.orientEdge(edge, normal)
207
first = math.radians(obj.FirstAngle)
208
last = math.radians(obj.LastAngle)
209
arc = Part.ArcOfCircle(circle, first, last)
210
nobj.addGeometry(arc)
211
addRadiusConstraint(edge)
214
elif tp in ["Wire", "Rectangle", "Polygon"] and obj.FilletRadius.Value == 0:
216
for edge in obj.Shape.Edges:
217
nobj.addGeometry(DraftGeomUtils.orientEdge(edge, normal))
219
closed = tp in ["Rectangle", "Polygon"] or obj.Closed
220
last = nobj.GeometryCount
221
segs = list(range(last - len(obj.Shape.Edges), last))
222
nexts = segs[1:] + ([segs[0]] if closed else [None])
223
for seg, next in zip(segs, nexts):
225
constraints.append(Constraint("Coincident",seg, end_point, next, start_point))
226
if DraftGeomUtils.isAligned(nobj.Geometry[seg], "x"):
227
constraints.append(Constraint("Vertical", seg))
228
elif DraftGeomUtils.isAligned(nobj.Geometry[seg], "y"):
229
constraints.append(Constraint("Horizontal", seg))
232
elif tp == "BSpline":
234
edge = DraftGeomUtils.orientEdge(obj.Shape.Edges[0], normal)
235
nobj.addGeometry(edge)
236
nobj.exposeInternalGeometry(nobj.GeometryCount-1)
239
elif tp == "BezCurve":
241
for piece in obj.Shape.Edges:
243
bsp = bez.toBSpline(bez.FirstParameter,bez.LastParameter).toShape()
244
edge = DraftGeomUtils.orientEdge(bsp.Edges[0], normal)
245
nobj.addGeometry(edge)
246
nobj.exposeInternalGeometry(nobj.GeometryCount-1)
251
shape = obj.Shape.copy()
253
shape.rotate(App.Base.Vector(0,0,0), axis, -1*angle)
254
point = Part.Point(shape.Point)
255
nobj.addGeometry(point)
258
elif tp == 'Shape' or hasattr(obj,'Shape'):
259
shape = obj if tp == 'Shape' else obj.Shape
261
for e in shape.Edges:
263
newedge = convertBezier(e)
264
nobj.addGeometry(DraftGeomUtils.orientEdge(
265
newedge, normal, make_arc=True))
266
addRadiusConstraint(newedge)
269
for wire in shape.Wires:
270
last_count = nobj.GeometryCount
271
edges = wire.OrderedEdges
273
newedge = convertBezier(edge)
274
nobj.addGeometry(DraftGeomUtils.orientEdge(
275
newedge, normal, make_arc=True))
276
addRadiusConstraint(newedge)
277
for i,g in enumerate(nobj.Geometry[last_count:]):
282
if DraftGeomUtils.isAligned(g,"x"):
283
constraints.append(Constraint("Vertical",seg))
284
elif DraftGeomUtils.isAligned(g,"y"):
285
constraints.append(Constraint("Horizontal",seg))
287
if seg == nobj.GeometryCount-1:
288
if not wire.isClosed():
290
g2 = nobj.Geometry[last_count]
294
g2 = nobj.Geometry[seg2]
296
end1 = g.value(g.LastParameter)
297
start2 = g2.value(g2.FirstParameter)
298
if DraftVecUtils.equals(end1,start2) :
299
constraints.append(Constraint(
300
"Coincident",seg,end_point,seg2,start_point))
302
end2 = g2.value(g2.LastParameter)
303
start1 = g.value(g.FirstParameter)
304
if DraftVecUtils.equals(end2,start1):
305
constraints.append(Constraint(
306
"Coincident",seg,start_point,seg2,end_point))
307
elif DraftVecUtils.equals(start1,start2):
308
constraints.append(Constraint(
309
"Coincident",seg,start_point,seg2,start_point))
310
elif DraftVecUtils.equals(end1,end2):
311
constraints.append(Constraint(
312
"Coincident",seg,end_point,seg2,end_point))
314
for wire in shape.Wires:
315
for edge in wire.OrderedEdges:
316
newedge = convertBezier(edge)
317
nobj.addGeometry(DraftGeomUtils.orientEdge(
318
newedge, normal, make_arc=True))
320
gui_utils.format_object(nobj,obj)
321
if ok and delete and hasattr(obj,'Shape'):
325
App.Console.PrintWarning(translate("draft",
326
"Cannot delete object {} with dependency".format(obj.Label))+"\n")
328
doc.removeObject(obj.Name)
334
objs = objs[1:] + obj.OutList
338
except Exception as ex:
339
App.Console.PrintWarning(translate("draft",
340
"Failed to delete object {}: {}".format(obj.Label,ex))+"\n")
343
nobj.addConstraint(constraints)
348
makeSketch = make_sketch