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.endPoint().x()
24 >>> line.endPoint().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, **kwargs):
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, **kwargs)
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 self._fillAttribute(constraint.refattr("ConstraintEntityA"), p1)
198 self._fillAttribute(constraint.refattr("ConstraintEntityB"), 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 self._fillAttribute(constraint.real("ConstraintValue"), 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 self._fillAttribute(constraint.refattr("ConstraintEntityA"), circle)
276 self._fillAttribute(constraint.real("ConstraintValue"), 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, *args):
312 """Set a fillet constraint between the 2 given lines with the given
315 constraint = self._feature.addFeature("SketchConstraintFillet")
317 line_1, line_2, radius = args
318 constraint.data().refattr("ConstraintEntityA").setObject(line_1)
319 constraint.data().reflist("ConstraintEntityB").clear()
320 constraint.data().reflist("ConstraintEntityB").append(line_2)
323 self._fillAttribute(constraint.data().refattrlist("ConstraintEntityA"), [point])
324 self._fillAttribute(constraint.real("ConstraintValue"), radius)
328 def setRigid(self, object_):
329 """Set a rigid constraint on a given object."""
330 constraint = self._feature.addFeature("SketchConstraintRigid")
331 self._fillAttribute(constraint.refattr("ConstraintEntityA"), object_)
335 #-------------------------------------------------------------
337 # Transformation constraints
339 #-------------------------------------------------------------
341 def addMirror(self, mirror_line, sketch_objects):
342 """Add a mirror transformation of the given objects to the sketch.
344 This transformation is a constraint.
346 :return: interface to the constraint
347 :rtype: Mirror object
349 mirror_constraint = self._feature.addFeature("SketchConstraintMirror")
350 mirror_interface = Mirror(mirror_constraint, mirror_line, sketch_objects)
352 return mirror_interface
355 #-------------------------------------------------------------
357 # Edition of Dimensional Constraints
359 #-------------------------------------------------------------
361 def setValue(self, constraint, value):
362 """Modify the value of the given dimensional constraint."""
363 constraint.data().real("ConstraintValue").setValue(value)
365 #-------------------------------------------------------------
367 # Macro functions combining geometry creation and constraints
369 #-------------------------------------------------------------
371 def addPolyline(self, *coords):
372 """Add a poly-line to this Sketch.
374 The end of consecutive segments are defined as coincident.
379 line_1 = self.addLine(c0, c1)
380 polyline.append(line_1)
381 # Adding and connecting next lines
382 for c2 in coords[2:]:
383 line_2 = self.addLine(c1, c2)
384 self.setCoincident(line_1.endPoint(), line_2.startPoint())
385 polyline.append(line_2)
390 def addPolygon(self, *coords):
391 """Add a polygon to this Sketch.
393 The end of consecutive segments are defined as coincident.
395 pg = self.addPolyline(*coords)
396 # Closing the poly-line supposed being defined by at least 3 points
398 cn = coords[len(coords) - 1]
399 ln = self.addLine(cn, c0)
401 pg[len(coords) - 2].endPoint(), ln.startPoint()
404 ln.endPoint(), pg[0].startPoint()
409 #-------------------------------------------------------------
413 #-------------------------------------------------------------
415 def selectFace(self, *args):
416 """Select the geometrical entities of this Sketch on which
417 the result Face must be built.
419 When no entity is given, the face is based on all existing
420 geometry of this Sketch.
423 wire = modelAPI_ResultConstruction(
424 self._feature.firstResult()
427 wire = args[0].shape()
429 raise Exception("not yet implemented")
430 # TODO: simple version now, should be a list of selected faces
431 return [Selection(self.result(), self.buildShape(wire))]
433 def buildShape(self, wire):
434 """Build the result Shape of this Sketch according to the
435 selected geometrical entities."""
436 o = self._origin.pnt()
437 dx = self._dir_x.dir()
440 # The faces are kept otherwise they are destroyed at exit
442 GeomAlgoAPI_SketchBuilder.createFaces(o, dx, n, wire, faces)
443 # TODO: Deal with several faces
447 """Returns the result data of this Feature."""
448 return self._feature.firstResult()