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
6 This interface allows to add a sketch
8 The created sketch object provides all the needed methods
9 for sketch modification and constraint edition.
17 >>> partset = model.moduleDocument()
18 >>> part = model.addPart(partset).document()
19 >>> plane = model.defaultPlane("XOY")
20 >>> sketch = model.addSketch(part, plane)
21 >>> line = sketch.addLine(0, 0, 0, 1)
22 >>> line.endPointData().x()
24 >>> line.endPointData().y()
28 from ModelAPI import modelAPI_ResultConstruction, featureToCompositeFeature
29 from GeomDataAPI import geomDataAPI_Point, geomDataAPI_Dir
30 from GeomAlgoAPI import GeomAlgoAPI_SketchBuilder, ShapeList
32 from model.sketcher.point import Point
33 from model.sketcher.line import Line
34 from model.sketcher.circle import Circle
35 from model.sketcher.arc import Arc
36 from model.sketcher.mirror import Mirror
37 from model.roots import Interface
38 from model.tools import Selection
41 def addSketch(document, plane):
42 """Add a sketch to a Part or PartSet.
45 document(ModelAPI_Document): part or partset document
46 plane(geom.Ax3): plane on wich the sketch is built
51 feature = featureToCompositeFeature(document.addFeature("Sketch"))
52 return Sketch(feature, plane)
54 class Sketch(Interface):
55 """Interface class for Sketch feature."""
56 def __init__(self, feature, *args):
57 """Initialize a 2D Sketch on the given plane.
59 The plane can be defined either by:
60 - a 3D axis system (geom.Ax3),
61 - an existing face identified by its topological name.
63 Interface.__init__(self, feature)
64 assert(self._feature.getKind() == "Sketch")
66 self._origin = geomDataAPI_Point(
67 self._feature.data().attribute("Origin")
69 self._dir_x = geomDataAPI_Dir(
70 self._feature.data().attribute("DirX")
72 self._norm = geomDataAPI_Dir(
73 self._feature.data().attribute("Norm")
75 self._external = self._feature.data().selection("External")
77 # If no arguments are given the attributes of the feature
81 if isinstance(plane, str):
82 self.__sketchOnFace(plane)
84 self.__sketchOnPlane(plane)
86 def __sketchOnPlane(self, plane):
87 """Create the sketch on a plane."""
88 origin = plane.location()
89 normal = plane.direction()
90 x_direction = plane.xDirection()
91 self._origin.setValue(origin.x(), origin.y(), origin.z())
92 self._norm.setValue(normal.x(), normal.y(), normal.z())
93 self._dir_x.setValue(x_direction.x(), x_direction.y(), x_direction.z())
95 def __sketchOnFace(self, name):
96 """Initialize the sketch on a face given by its name."""
97 self._external.selectSubShape("FACE", name)
99 #-------------------------------------------------------------
101 # Creation of Geometries
103 #-------------------------------------------------------------
105 def addPoint(self, *args):
106 """Add a point to the sketch."""
108 raise TypeError("No arguments given")
109 point_feature = self._feature.addFeature("SketchPoint")
110 return Point(point_feature, *args)
112 def addLine(self, *args):
113 """Add a line to the sketch.
115 .. function:: addLine(name)
116 Select an existing line. The line is added to the sketch with a rigid
117 constraint (it cannot be modified by the sketch)
120 name(str): name of an existing line
122 .. function:: addLine(start, end)
123 Create a line by points
126 start(point): start point of the line
127 end(point): end point of the line
129 .. function:: addLine(start_x, start_y, end_x, end_y)
130 Create a line by coordinates
133 start_x(double): start point x coordinate
136 raise TypeError("No arguments given")
137 line_feature = self._feature.addFeature("SketchLine")
138 line_interface = Line(line_feature, *args)
139 # if the line is created by name add a rigid constraint
140 # to the created line
141 if len(args) == 1 and isinstance(args[0], str):
142 constraint = self._feature.addFeature("SketchConstraintRigid")
143 constraint.refattr("ConstraintEntityA").setObject(
144 line_feature.firstResult()
146 return line_interface
148 def addCircle(self, *args):
149 """Add a circle to this Sketch."""
151 raise TypeError("No arguments given")
152 circle_feature = self._feature.addFeature("SketchCircle")
153 return Circle(circle_feature, *args)
155 def addArc(self, *args):
156 """Add an arc of circle to the sketch and return an arc object.
158 Two different syntaxes are allowed:
160 .. function:: addArc(center, start, end)
163 center (point): center of the arc
164 start (point): start point of the arc
165 end (point): end point of the arc
167 .. function:: addArc(center_x, center_y, start_x, start_y, end_x, end_y)
169 Same as above but with coordinates
174 TypeError: if no argument is provided
177 raise TypeError("No arguments given")
178 arc_feature = self._feature.addFeature("SketchArc")
179 return Arc(arc_feature, *args)
181 #-------------------------------------------------------------
183 # Creation of Geometrical and Dimensional Constraints
185 #-------------------------------------------------------------
187 def setCoincident(self, p1, p2):
188 """Set coincident the two given points and add the corresponding
189 constraint to this Sketch."""
190 # assert(p1 and p2) NOTE : if an argument is missing python
191 # will raise TypeError by itself.
192 # It seems better to check only that provided arguments are not
194 if p1 is None or p2 is None:
195 raise TypeError("NoneType argument given")
196 constraint = self._feature.addFeature("SketchConstraintCoincidence")
197 constraint.data().refattr("ConstraintEntityA").setAttr(p1)
198 constraint.data().refattr("ConstraintEntityB").setAttr(p2)
202 def setParallel(self, l1, l2):
203 """Set parallel the two given lines and add the corresponding
204 constraint to this Sketch."""
205 if l1 is None or l2 is None:
206 raise TypeError("NoneType argument given")
207 constraint = self._feature.addFeature("SketchConstraintParallel")
208 constraint.data().refattr("ConstraintEntityA").setObject(l1)
209 constraint.data().refattr("ConstraintEntityB").setObject(l2)
213 def setPerpendicular(self, l1, l2):
214 """Set perpendicular the two given lines and add the corresponding
215 constraint to this Sketch."""
216 if l1 is None or l2 is None:
217 raise TypeError("NoneType argument given")
218 constraint = self._feature.addFeature("SketchConstraintPerpendicular")
219 constraint.data().refattr("ConstraintEntityA").setObject(l1)
220 constraint.data().refattr("ConstraintEntityB").setObject(l2)
224 def setHorizontal(self, line):
225 """Set horizontal the given line and add the corresponding
226 constraint to this Sketch."""
228 raise TypeError("NoneType argument given")
229 constraint = self._feature.addFeature("SketchConstraintHorizontal")
230 constraint.data().refattr("ConstraintEntityA").setObject(line)
234 def setVertical(self, line):
235 """Set vertical the given line and add the corresponding
236 constraint to this Sketch."""
238 raise TypeError("NoneType argument given")
239 constraint = self._feature.addFeature("SketchConstraintVertical")
240 constraint.data().refattr("ConstraintEntityA").setObject(line)
244 def setDistance(self, point, line, length):
245 """Set the distance between the given point and line, and add
246 the corresponding constraint to this Sketch."""
247 if point is None or line is None:
248 raise TypeError("NoneType argument given")
249 constraint = self._feature.addFeature("SketchConstraintDistance")
250 if isinstance(line, basestring):
251 # Add the edge identified by the given topological name
253 line = self.addLine(line).result()
254 constraint.data().refattr("ConstraintEntityA").setAttr(point)
255 constraint.data().refattr("ConstraintEntityB").setObject(line)
256 constraint.data().real("ConstraintValue").setValue(length)
260 def setLength(self, line, length):
261 """Set the length of the given line and add the corresponding
262 constraint to this Sketch."""
264 raise TypeError("NoneType argument given")
265 constraint = self._feature.addFeature("SketchConstraintLength")
266 constraint.data().refattr("ConstraintEntityA").setObject(line)
267 constraint.data().real("ConstraintValue").setValue(length)
271 def setRadius(self, circle, radius):
272 """Set the radius of the given circle and add the corresponding
273 constraint to this Sketch."""
274 constraint = self._feature.addFeature("SketchConstraintRadius")
275 constraint.data().refattr("ConstraintEntityA").setObject(circle)
276 constraint.data().real("ConstraintValue").setValue(radius)
280 def setEqual(self, object_1, object_2):
281 """Set the radii of two circles or the length of two lines equal.
283 The corresponding constraint is added to the sketch"""
284 constraint = self._feature.addFeature("SketchConstraintEqual")
285 constraint.data().refattr("ConstraintEntityA").setObject(object_1)
286 constraint.data().refattr("ConstraintEntityB").setObject(object_2)
290 def setAngle(self, line_1, line_2, angle):
291 """Set the angle between the given 2 lines and add the corresponding
292 constraint to the sketch."""
293 constraint = self._feature.addFeature("SketchConstraintAngle")
294 constraint.data().refattr("ConstraintEntityA").setObject(line_1)
295 constraint.data().refattr("ConstraintEntityB").setObject(line_2)
296 constraint.data().real("ConstraintValue").setValue(angle)
300 def setTangent(self, object_1, object_2):
301 """Set a tangential continuity between two objects
302 at their coincidence point."""
303 if object_1 is None or object_2 is None:
304 raise TypeError("NoneType argument given")
305 constraint = self._feature.addFeature("SketchConstraintTangent")
306 constraint.data().refattr("ConstraintEntityA").setObject(object_1)
307 constraint.data().refattr("ConstraintEntityB").setObject(object_2)
311 def setFillet(self, line_1, line_2, radius):
312 """Set a fillet constraint between the 2 given lines with the given
314 constraint = self._feature.addFeature("SketchConstraintFillet")
315 constraint.data().refattr("ConstraintEntityA").setObject(line_1)
316 constraint.data().reflist("ConstraintEntityB").clear()
317 constraint.data().reflist("ConstraintEntityB").append(line_2)
321 def setRigid(self, object_):
322 """Set a rigid constraint on a given object."""
323 constraint = self._feature.addFeature("SketchConstraintRigid")
324 constraint.data().refattr("ConstraintEntityA").setObject(object_)
328 #-------------------------------------------------------------
330 # Transformation constraints
332 #-------------------------------------------------------------
334 def addMirror(self, mirror_line, sketch_objects):
335 """Add a mirror transformation of the given objects to the sketch.
337 This transformation is a constraint.
339 :return: interface to the constraint
340 :rtype: Mirror object
342 mirror_constraint = self._feature.addFeature("SketchConstraintMirror")
343 mirror_interface = Mirror(mirror_constraint, mirror_line, sketch_objects)
345 return mirror_interface
348 #-------------------------------------------------------------
350 # Edition of Dimensional Constraints
352 #-------------------------------------------------------------
354 def setValue(self, constraint, value):
355 """Modify the value of the given dimensional constraint."""
356 constraint.data().real("ConstraintValue").setValue(value)
358 #-------------------------------------------------------------
360 # Macro functions combining geometry creation and constraints
362 #-------------------------------------------------------------
364 def addPolyline(self, *coords):
365 """Add a poly-line to this Sketch.
367 The end of consecutive segments are defined as coincident.
372 line_1 = self.addLine(c0, c1)
373 polyline.append(line_1)
374 # Adding and connecting next lines
375 for c2 in coords[2:]:
376 line_2 = self.addLine(c1, c2)
377 self.setCoincident(line_1.endPointData(), line_2.startPointData())
378 polyline.append(line_2)
383 def addPolygon(self, *coords):
384 """Add a polygon to this Sketch.
386 The end of consecutive segments are defined as coincident.
388 pg = self.addPolyline(*coords)
389 # Closing the poly-line supposed being defined by at least 3 points
391 cn = coords[len(coords) - 1]
392 ln = self.addLine(cn, c0)
394 pg[len(coords) - 2].endPointData(), ln.startPointData()
397 ln.endPointData(), pg[0].startPointData()
402 #-------------------------------------------------------------
406 #-------------------------------------------------------------
408 def selectFace(self, *args):
409 """Select the geometrical entities of this Sketch on which
410 the result Face must be built.
412 When no entity is given, the face is based on all existing
413 geometry of this Sketch.
416 wire = modelAPI_ResultConstruction(
417 self._feature.firstResult()
420 wire = args[0].shape()
422 raise Exception("not yet implemented")
423 # TODO: simple version now, should be a list of selected faces
424 return [Selection(self.result(), self.buildShape(wire))]
426 def buildShape(self, wire):
427 """Build the result Shape of this Sketch according to the
428 selected geometrical entities."""
429 o = self._origin.pnt()
430 dx = self._dir_x.dir()
433 # The faces are kept otherwise they are destroyed at exit
435 GeomAlgoAPI_SketchBuilder.createFaces(o, dx, n, wire, faces)
436 # TODO: Deal with several faces
440 """Returns the result data of this Feature."""
441 return self._feature.firstResult()