1 # Author: Daniel Brunier-Coulin with contribution by Mikhail Ponikarov
2 # finalized by Renaud Nedelec and Sergey Pokhodenko
3 # Copyright (C) 2014-20xx CEA/DEN, EDF R&D
7 This interface allows to add a sketch
9 The created sketch object provides all the needed methods
10 for sketch modification and constraint edition.
18 >>> partset = model.moduleDocument()
19 >>> part = model.addPart(partset).document()
20 >>> plane = model.defaultPlane("XOY")
21 >>> sketch = model.addSketch(part, plane)
22 >>> line = sketch.addLine(0, 0, 0, 1)
25 from ModelAPI import modelAPI_ResultConstruction, featureToCompositeFeature
26 from GeomDataAPI import geomDataAPI_Point, geomDataAPI_Dir
27 from GeomAlgoAPI import GeomAlgoAPI_SketchBuilder, ShapeList
29 from model.sketcher.point import Point
30 from model.sketcher.line import Line
31 from model.sketcher.circle import Circle
32 from model.sketcher.arc import Arc
33 from model.sketcher.mirror import Mirror
34 from model.roots import Interface
35 from model.tools import Selection
38 def addSketch(document, plane):
39 """Add a sketch to a Part or PartSet.
42 document(ModelAPI_Document): part or partset document
43 plane(geom.Ax3): plane on wich the sketch is built
48 feature = featureToCompositeFeature(doc.addFeature("Sketch"))
49 return Sketch(feature, plane)
51 class Sketch(Interface):
52 """Interface class for Sketch feature."""
53 def __init__(self, feature, *args):
54 """Initialize a 2D Sketch on the given plane.
56 The plane can be defined either by:
57 - a 3D axis system (geom.Ax3),
58 - an existing face identified by its topological name.
60 Interface.__init__(self, feature)
61 assert(self._feature.getKind() == "Sketch")
63 self._origin = geomDataAPI_Point(
64 self._feature.data().attribute("Origin")
66 self._dir_x = geomDataAPI_Dir(
67 self._feature.data().attribute("DirX")
69 self._norm = geomDataAPI_Dir(
70 self._feature.data().attribute("Norm")
72 self._external = self._feature.data().selection("External")
74 # If no arguments are given the attributes of the feature
78 if isinstance(plane, str):
79 self.__sketchOnFace(plane)
81 self.__sketchOnPlane(plane)
83 def __sketchOnPlane(self, plane):
84 """Create the sketch on a plane."""
85 origin = plane.location()
86 normal = plane.direction()
87 x_direction = plane.xDirection()
88 self._origin.setValue(origin.x(), origin.y(), origin.z())
89 self._norm.setValue(normal.x(), normal.y(), normal.z())
90 self._dir_x.setValue(x_direction.x(), x_direction.y(), x_direction.z())
92 def __sketchOnFace(self, name):
93 """Initialize the sketch on a face given by its name."""
94 self._external.selectSubShape("FACE", name)
96 #-------------------------------------------------------------
98 # Creation of Geometries
100 #-------------------------------------------------------------
102 def addPoint(self, *args):
103 """Add a point to the sketch."""
105 raise TypeError("No arguments given")
106 point_feature = self._feature.addFeature("SketchPoint")
107 return Point(point_feature, *args)
109 def addLine(self, *args):
110 """Add a line to the sketch.
112 .. function:: addLine(name)
113 Select an existing line. The line is added to the sketch with a rigid
114 constraint (it cannot be modified by the sketch)
117 name(str): name of an existing line
119 .. function:: addLine(start, end)
120 Create a line by points
123 start(point): start point of the line
124 end(point): end point of the line
126 .. function:: addLine(start_x, start_y, end_x, end_y)
127 Create a line by coordinates
130 start_x(double): start point x coordinate
133 raise TypeError("No arguments given")
134 line_feature = self._feature.addFeature("SketchLine")
135 line_interface = Line(line_feature, *args)
136 # if the line is created by name add a rigid constraint
137 # to the created line
138 if len(args) == 1 and isinstance(args[0], str):
139 constraint = self._feature.addFeature("SketchConstraintRigid")
140 constraint.refattr("ConstraintEntityA").setObject(
141 line_feature.firstResult()
143 return line_interface
145 def addCircle(self, *args):
146 """Add a circle to this Sketch."""
148 raise TypeError("No arguments given")
149 circle_feature = self._feature.addFeature("SketchCircle")
150 return Circle(circle_feature, *args)
152 def addArc(self, *args):
153 """Add an arc of circle to the sketch and return an arc object.
155 Two different syntaxes are allowed:
157 .. function:: addArc(center, start, end)
160 center (point): center of the arc
161 start (point): start point of the arc
162 end (point): end point of the arc
164 .. function:: addArc(center_x, center_y, start_x, start_y, end_x, end_y)
166 Same as above but with coordinates
171 TypeError: if no argument is provided
174 raise TypeError("No arguments given")
175 arc_feature = self._feature.addFeature("SketchArc")
176 return Arc(arc_feature, *args)
178 #-------------------------------------------------------------
180 # Creation of Geometrical and Dimensional Constraints
182 #-------------------------------------------------------------
184 def setCoincident(self, p1, p2):
185 """Set coincident the two given points and add the corresponding
186 constraint to this Sketch."""
187 # assert(p1 and p2) NOTE : if an argument is missing python
188 # will raise TypeError by itself.
189 # It seems better to check only that provided arguments are not
191 if p1 is None or p2 is None:
192 raise TypeError("NoneType argument given")
193 constraint = self._feature.addFeature("SketchConstraintCoincidence")
194 constraint.data().refattr("ConstraintEntityA").setAttr(p1)
195 constraint.data().refattr("ConstraintEntityB").setAttr(p2)
199 def setParallel(self, l1, l2):
200 """Set parallel the two given lines and add the corresponding
201 constraint to this Sketch."""
202 if l1 is None or l2 is None:
203 raise TypeError("NoneType argument given")
204 constraint = self._feature.addFeature("SketchConstraintParallel")
205 constraint.data().refattr("ConstraintEntityA").setObject(l1)
206 constraint.data().refattr("ConstraintEntityB").setObject(l2)
210 def setPerpendicular(self, l1, l2):
211 """Set perpendicular the two given lines and add the corresponding
212 constraint to this Sketch."""
213 if l1 is None or l2 is None:
214 raise TypeError("NoneType argument given")
215 constraint = self._feature.addFeature("SketchConstraintPerpendicular")
216 constraint.data().refattr("ConstraintEntityA").setObject(l1)
217 constraint.data().refattr("ConstraintEntityB").setObject(l2)
221 def setHorizontal(self, line):
222 """Set horizontal the given line and add the corresponding
223 constraint to this Sketch."""
225 raise TypeError("NoneType argument given")
226 constraint = self._feature.addFeature("SketchConstraintHorizontal")
227 constraint.data().refattr("ConstraintEntityA").setObject(line)
231 def setVertical(self, line):
232 """Set vertical the given line and add the corresponding
233 constraint to this Sketch."""
235 raise TypeError("NoneType argument given")
236 constraint = self._feature.addFeature("SketchConstraintVertical")
237 constraint.data().refattr("ConstraintEntityA").setObject(line)
241 def setDistance(self, point, line, length):
242 """Set the distance between the given point and line, and add
243 the corresponding constraint to this Sketch."""
244 if point is None or line is None:
245 raise TypeError("NoneType argument given")
246 constraint = self._feature.addFeature("SketchConstraintDistance")
247 if isinstance(line, basestring):
248 # Add the edge identified by the given topological name
250 line = self.addLine(line).result()
251 constraint.data().refattr("ConstraintEntityA").setAttr(point)
252 constraint.data().refattr("ConstraintEntityB").setObject(line)
253 constraint.data().real("ConstraintValue").setValue(length)
257 def setLength(self, line, length):
258 """Set the length of the given line and add the corresponding
259 constraint to this Sketch."""
261 raise TypeError("NoneType argument given")
262 constraint = self._feature.addFeature("SketchConstraintLength")
263 constraint.data().refattr("ConstraintEntityA").setObject(line)
264 constraint.data().real("ConstraintValue").setValue(length)
268 def setRadius(self, circle, radius):
269 """Set the radius of the given circle and add the corresponding
270 constraint to this Sketch."""
271 constraint = self._feature.addFeature("SketchConstraintRadius")
272 constraint.data().refattr("ConstraintEntityA").setObject(circle)
273 constraint.data().real("ConstraintValue").setValue(radius)
277 def setEqual(self, object_1, object_2):
278 """Set the radii of two circles or the length of two lines equal.
280 The corresponding constraint is added to the sketch"""
281 constraint = self._feature.addFeature("SketchConstraintEqual")
282 constraint.data().refattr("ConstraintEntityA").setObject(object_1)
283 constraint.data().refattr("ConstraintEntityB").setObject(object_2)
287 def setAngle(self, line_1, line_2, angle):
288 """Set the angle between the given 2 lines and add the corresponding
289 constraint to the sketch."""
290 constraint = self._feature.addFeature("SketchConstraintAngle")
291 constraint.data().refattr("ConstraintEntityA").setObject(line_1)
292 constraint.data().refattr("ConstraintEntityB").setObject(line_2)
293 constraint.data().real("ConstraintValue").setValue(angle)
297 def setTangent(self, object_1, object_2):
298 """Set a tangential continuity between two objects
299 at their coincidence point."""
300 if object_1 is None or object_2 is None:
301 raise TypeError("NoneType argument given")
302 constraint = self._feature.addFeature("SketchConstraintTangent")
303 constraint.data().refattr("ConstraintEntityA").setObject(object_1)
304 constraint.data().refattr("ConstraintEntityB").setObject(object_2)
308 def setFillet(self, line_1, line_2, radius):
309 """Set a fillet constraint between the 2 given lines with the given
311 constraint = self._feature.addFeature("SketchConstraintFillet")
312 constraint.data().refattr("ConstraintEntityA").setObject(line_1)
313 constraint.data().reflist("ConstraintEntityB").clear()
314 constraint.data().reflist("ConstraintEntityB").append(line_2)
318 def setRigid(self, object_):
319 """Set a rigid constraint on a given object."""
320 constraint = self._feature.addFeature("SketchConstraintRigid")
321 constraint.data().refattr("ConstraintEntityA").setObject(object_)
325 #-------------------------------------------------------------
327 # Transformation constraints
329 #-------------------------------------------------------------
331 def addMirror(self, mirror_line, sketch_objects):
332 """Add a mirror transformation of the given objects to the sketch.
334 This transformation is a constraint.
336 :return: interface to the constraint
337 :rtype: Mirror object
339 mirror_constraint = self._feature.addFeature("SketchConstraintMirror")
340 mirror_interface = Mirror(mirror_constraint, mirror_line, sketch_objects)
342 return mirror_interface
345 #-------------------------------------------------------------
347 # Edition of Dimensional Constraints
349 #-------------------------------------------------------------
351 def setValue(self, constraint, value):
352 """Modify the value of the given dimensional constraint."""
353 constraint.data().real("ConstraintValue").setValue(value)
355 #-------------------------------------------------------------
357 # Macro functions combining geometry creation and constraints
359 #-------------------------------------------------------------
361 def addPolyline(self, *coords):
362 """Add a poly-line to this Sketch.
364 The end of consecutive segments are defined as coincident.
369 line_1 = self.addLine(c0, c1)
370 polyline.append(line_1)
371 # Adding and connecting next lines
372 for c2 in coords[2:]:
373 line_2 = self.addLine(c1, c2)
374 self.setCoincident(line_1.endPointData(), line_2.startPointData())
375 polyline.append(line_2)
380 def addPolygon(self, *coords):
381 """Add a polygon to this Sketch.
383 The end of consecutive segments are defined as coincident.
385 pg = self.addPolyline(*coords)
386 # Closing the poly-line supposed being defined by at least 3 points
388 cn = coords[len(coords) - 1]
389 ln = self.addLine(cn, c0)
391 pg[len(coords) - 2].endPointData(), ln.startPointData()
394 ln.endPointData(), pg[0].startPointData()
399 #-------------------------------------------------------------
403 #-------------------------------------------------------------
405 def selectFace(self, *args):
406 """Select the geometrical entities of this Sketch on which
407 the result Face must be built.
409 When no entity is given, the face is based on all existing
410 geometry of this Sketch.
413 wire = modelAPI_ResultConstruction(
414 self._feature.firstResult()
417 wire = args[0].shape()
419 raise Exception("not yet implemented")
420 # TODO: simple version now, should be a list of selected faces
421 return [Selection(self.result(), self.buildShape(wire))]
423 def buildShape(self, wire):
424 """Build the result Shape of this Sketch according to the
425 selected geometrical entities."""
426 o = self._origin.pnt()
427 dx = self._dir_x.dir()
430 # The faces are kept otherwise they are destroyed at exit
432 GeomAlgoAPI_SketchBuilder.createFaces(o, dx, n, wire, faces)
433 # TODO: Deal with several faces
437 """Returns the result data of this Feature."""
438 return self._feature.firstResult()