]> SALOME platform Git repositories - modules/shaper.git/blob - src/PythonAPI/model/sketcher/sketch.py
Salome HOME
[PythonAPI] Sketch circle interface modification (example of new API style discussed...
[modules/shaper.git] / src / PythonAPI / model / sketcher / sketch.py
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
4
5 """Sketch Feature Interface
6
7 This interface allows to add a Sketch
8 in a Part.
9 The created sketch object provides all the needed methods 
10 for sketch modification and constraint edition.
11 """
12
13 from ModelAPI import modelAPI_ResultConstruction, featureToCompositeFeature
14 from GeomDataAPI import geomDataAPI_Point, geomDataAPI_Dir
15 from GeomAlgoAPI import GeomAlgoAPI_SketchBuilder, ShapeList
16
17 from model.sketcher.point import Point
18 from model.sketcher.line import Line
19 from model.sketcher.circle import Circle
20 from model.sketcher.arc import Arc
21 from model.sketcher.mirror import Mirror
22 from model.roots import Interface
23 from model.tools import Selection
24
25
26 def addSketch(doc, plane):
27     """Add a Sketch feature to the Part or PartSet and return an interface
28     on it.
29
30     A Sketch object is instanciated with a feature as input parameter
31     it provides an interface for manipulation of the feature data.
32     
33     :return: interface on the feature
34     :rtype: Sketch"""
35     feature = featureToCompositeFeature(doc.addFeature("Sketch"))
36     return Sketch(feature, plane)
37
38 class Sketch(Interface):
39     """Interface class for Sketch feature."""
40     def __init__(self, feature, *args):
41         """Initialize a 2D Sketch on the given plane.
42
43         The plane can be defined either by:
44         - a 3D axis system (geom.Ax3),
45         - an existing face identified by its topological name.
46         """
47         Interface.__init__(self, feature)
48         assert(self._feature.getKind() == "Sketch")
49
50         self._origin = geomDataAPI_Point(
51             self._feature.data().attribute("Origin")
52             )
53         self._dir_x = geomDataAPI_Dir(
54             self._feature.data().attribute("DirX")
55             )
56         self._norm = geomDataAPI_Dir(
57             self._feature.data().attribute("Norm")
58             )
59         self._external = self._feature.data().selection("External")
60
61         # If no arguments are given the attributes of the feature 
62         # are not Initialized
63         if args is not None:
64             plane = args[0]
65             if isinstance(plane, str):
66                 self.__sketchOnFace(plane)
67             else:
68                 self.__sketchOnPlane(plane)
69
70     def __sketchOnPlane(self, plane):
71         """Create the sketch on a plane."""
72         origin = plane.location()
73         normal = plane.direction()
74         x_direction = plane.xDirection()
75         self._origin.setValue(origin.x(), origin.y(), origin.z())
76         self._norm.setValue(normal.x(), normal.y(), normal.z())
77         self._dir_x.setValue(x_direction.x(), x_direction.y(), x_direction.z())
78
79     def __sketchOnFace(self, name):
80         """Initialize the sketch on a face given by its name."""
81         self._external.selectSubShape("FACE", name)
82
83     #-------------------------------------------------------------
84     #
85     # Creation of Geometries
86     #
87     #-------------------------------------------------------------
88
89     def addPoint(self, *args):
90         """Add a point to this Sketch."""
91         if not args:
92             raise TypeError("No arguments given")
93         point_feature = self._feature.addFeature("SketchPoint")
94         return Point(point_feature, *args)
95
96     def addLine(self, *args):
97         """Add a line to this Sketch."""
98         if not args:
99             raise TypeError("No arguments given")
100         line_feature = self._feature.addFeature("SketchLine")
101         line_interface = Line(line_feature, *args)
102         # if the line is created by name add a rigid constraint
103         # to the created line
104         if len(args) == 1 and isinstance(args[0], str):
105             constraint = self._feature.addFeature("SketchConstraintRigid")
106             constraint.refattr("ConstraintEntityA").setObject(
107                 line_feature.firstResult()
108                 )
109         return line_interface
110
111     def addCircle(self, *args):
112         """Add a circle to this Sketch."""
113         if not args:
114             raise TypeError("No arguments given")
115         circle_feature = self._feature.addFeature("SketchCircle")
116         return Circle(circle_feature, *args)
117
118     def addArc(self, *args):
119         """Add an arc to the sketch.
120         
121         :param sequence args: A sequence of arguments that can be:
122         
123            * The center, start and end points
124            * The center, start and end points coordinates
125         :return: arc object
126         :rtype: :class:`model.sketcher.Arc`
127         :raises TypeError: if no argument is provided
128         """
129         if not args:
130             raise TypeError("No arguments given")
131         arc_feature = self._feature.addFeature("SketchArc")
132         return Arc(arc_feature, *args)
133
134     #-------------------------------------------------------------
135     #
136     # Creation of Geometrical and Dimensional Constraints
137     #
138     #-------------------------------------------------------------
139
140     def setCoincident(self, p1, p2):
141         """Set coincident the two given points and add the corresponding
142         constraint to this Sketch."""
143         # assert(p1 and p2) NOTE : if an argument is missing python
144         # will raise TypeError by itself.
145         # It seems better to check only that provided arguments are not 
146         # None
147         if p1 is None or p2 is None:
148             raise TypeError("NoneType argument given")
149         constraint = self._feature.addFeature("SketchConstraintCoincidence")
150         constraint.data().refattr("ConstraintEntityA").setAttr(p1)
151         constraint.data().refattr("ConstraintEntityB").setAttr(p2)
152         self.execute()
153         return constraint
154
155     def setParallel(self, l1, l2):
156         """Set parallel the two given lines and add the corresponding
157         constraint to this Sketch."""
158         if l1 is None or l2 is None:
159             raise TypeError("NoneType argument given")
160         constraint = self._feature.addFeature("SketchConstraintParallel")
161         constraint.data().refattr("ConstraintEntityA").setObject(l1)
162         constraint.data().refattr("ConstraintEntityB").setObject(l2)
163         self.execute()
164         return constraint
165
166     def setPerpendicular(self, l1, l2):
167         """Set perpendicular the two given lines and add the corresponding
168         constraint to this Sketch."""
169         if l1 is None or l2 is None:
170             raise TypeError("NoneType argument given")
171         constraint = self._feature.addFeature("SketchConstraintPerpendicular")
172         constraint.data().refattr("ConstraintEntityA").setObject(l1)
173         constraint.data().refattr("ConstraintEntityB").setObject(l2)
174         self.execute()
175         return constraint
176
177     def setHorizontal(self, line):
178         """Set horizontal the given line and add the corresponding
179         constraint to this Sketch."""
180         if line is None:
181             raise TypeError("NoneType argument given")
182         constraint = self._feature.addFeature("SketchConstraintHorizontal")
183         constraint.data().refattr("ConstraintEntityA").setObject(line)
184         self.execute()
185         return constraint
186
187     def setVertical(self, line):
188         """Set vertical the given line and add the corresponding
189         constraint to this Sketch."""
190         if line is None:
191             raise TypeError("NoneType argument given")
192         constraint = self._feature.addFeature("SketchConstraintVertical")
193         constraint.data().refattr("ConstraintEntityA").setObject(line)
194         self.execute()
195         return constraint
196
197     def setDistance(self, point, line, length):
198         """Set the distance between the given point and line, and add
199         the corresponding constraint to this Sketch."""
200         if point is None or line is None:
201             raise TypeError("NoneType argument given")
202         constraint = self._feature.addFeature("SketchConstraintDistance")
203         if isinstance(line, basestring):
204             # Add the edge identified by the given topological name
205             # to this Sketch
206             line = self.addLine(line).result()
207         constraint.data().refattr("ConstraintEntityA").setAttr(point)
208         constraint.data().refattr("ConstraintEntityB").setObject(line)
209         constraint.data().real("ConstraintValue").setValue(length)
210         self.execute()
211         return constraint
212
213     def setLength(self, line, length):
214         """Set the length of the given line and add the corresponding
215         constraint to this Sketch."""
216         if line is None:
217             raise TypeError("NoneType argument given")
218         constraint = self._feature.addFeature("SketchConstraintLength")
219         constraint.data().refattr("ConstraintEntityA").setObject(line)
220         constraint.data().real("ConstraintValue").setValue(length)
221         self.execute()
222         return constraint
223
224     def setRadius(self, circle, radius):
225         """Set the radius of the given circle and add the corresponding
226         constraint to this Sketch."""
227         constraint = self._feature.addFeature("SketchConstraintRadius")
228         constraint.data().refattr("ConstraintEntityA").setObject(circle)
229         constraint.data().real("ConstraintValue").setValue(radius)
230         self.execute()
231         return constraint
232
233     def setEqual(self, object_1, object_2):
234         """Set the radii of two circles or the length of two lines equal.
235
236         The corresponding constraint is added to the sketch"""
237         constraint = self._feature.addFeature("SketchConstraintEqual")
238         constraint.data().refattr("ConstraintEntityA").setObject(object_1)
239         constraint.data().refattr("ConstraintEntityB").setObject(object_2)
240         self.execute()
241         return constraint
242
243     def setAngle(self, line_1, line_2, angle):
244         """Set the angle between the given 2 lines and add the corresponding
245         constraint to the sketch."""
246         constraint = self._feature.addFeature("SketchConstraintAngle")
247         constraint.data().refattr("ConstraintEntityA").setObject(line_1)
248         constraint.data().refattr("ConstraintEntityB").setObject(line_2)
249         constraint.data().real("ConstraintValue").setValue(angle)
250         self.execute()
251         return constraint
252
253     def setTangent(self, object_1, object_2):
254         """Set a tangential continuity between two objects
255         at their coincidence point."""
256         if object_1 is None or object_2 is None:
257             raise TypeError("NoneType argument given")
258         constraint = self._feature.addFeature("SketchConstraintTangent")
259         constraint.data().refattr("ConstraintEntityA").setObject(object_1)
260         constraint.data().refattr("ConstraintEntityB").setObject(object_2)
261         self.execute()
262         return constraint
263
264     def setFillet(self, line_1, line_2, radius):
265         """Set a fillet constraint between the 2 given lines with the given
266         filleting radius."""
267         constraint = self._feature.addFeature("SketchConstraintFillet")
268         constraint.data().refattr("ConstraintEntityA").setObject(line_1)
269         constraint.data().reflist("ConstraintEntityB").clear()
270         constraint.data().reflist("ConstraintEntityB").append(line_2)
271         self.execute()
272         return constraint
273     
274     def setRigid(self, object_):
275         """Set a rigid constraint on a given object."""
276         constraint = self._feature.addFeature("SketchConstraintRigid")
277         constraint.data().refattr("ConstraintEntityA").setObject(object_)
278         self.execute()
279         return constraint
280     
281     #-------------------------------------------------------------
282     #
283     # Transformation constraints
284     #
285     #-------------------------------------------------------------
286     
287     def addMirror(self, mirror_line, sketch_objects):
288         """Add a mirror transformation of the given objects to the sketch.
289         
290         This transformation is a constraint.
291         
292         :return: interface to the constraint
293         :rtype: Mirror object
294         """
295         mirror_constraint = self._feature.addFeature("SketchConstraintMirror")
296         mirror_interface = Mirror(mirror_constraint, mirror_line, sketch_objects)
297         self.execute()
298         return mirror_interface
299         
300
301     #-------------------------------------------------------------
302     #
303     # Edition of Dimensional Constraints
304     #
305     #-------------------------------------------------------------
306
307     def setValue(self, constraint, value):
308         """Modify the value of the given dimensional constraint."""
309         constraint.data().real("ConstraintValue").setValue(value)
310
311     #-------------------------------------------------------------
312     #
313     # Macro functions combining geometry creation and constraints
314     #
315     #-------------------------------------------------------------
316
317     def addPolyline(self, *coords):
318         """Add a poly-line to this Sketch.
319
320         The end of consecutive segments are defined as coincident.
321         """
322         c0 = coords[0]
323         c1 = coords[1]
324         polyline = []
325         line_1 = self.addLine(c0, c1)
326         polyline.append(line_1)
327         # Adding and connecting next lines
328         for c2 in coords[2:]:
329             line_2 = self.addLine(c1, c2)
330             self.setCoincident(line_1.endPointData(), line_2.startPointData())
331             polyline.append(line_2)
332             c1 = c2
333             line_1 = line_2
334         return polyline
335
336     def addPolygon(self, *coords):
337         """Add a polygon to this Sketch.
338
339         The end of consecutive segments are defined as coincident.
340         """
341         pg = self.addPolyline(*coords)
342         # Closing the poly-line supposed being defined by at least 3 points
343         c0 = coords[0]
344         cn = coords[len(coords) - 1]
345         ln = self.addLine(cn, c0)
346         self.setCoincident(
347             pg[len(coords) - 2].endPointData(), ln.startPointData()
348             )
349         self.setCoincident(
350             ln.endPointData(), pg[0].startPointData()
351             )
352         pg.append(ln)
353         return pg
354
355     #-------------------------------------------------------------
356     #
357     # Getters
358     #
359     #-------------------------------------------------------------
360
361     def selectFace(self, *args):
362         """Select the geometrical entities of this Sketch on which
363         the result Face must be built.
364
365         When no entity is given, the face is based on all existing
366         geometry of this Sketch.
367         """
368         if len(args) == 0:
369             wire = modelAPI_ResultConstruction(
370                 self._feature.firstResult()
371                 ).shape()
372         elif len(args) == 1:
373             wire = args[0].shape()
374         else:
375             raise Exception("not yet implemented")
376         # TODO: simple version now, should be a list of selected faces
377         return [Selection(self.result(), self.buildShape(wire))]
378
379     def buildShape(self, wire):
380         """Build the result Shape of this Sketch according to the
381         selected geometrical entities."""
382         o = self._origin.pnt()
383         dx = self._dir_x.dir()
384         n = self._norm.dir()
385
386         # The faces are kept otherwise they are destroyed at exit
387         faces = ShapeList()
388         GeomAlgoAPI_SketchBuilder.createFaces(o, dx, n, wire, faces)
389         # TODO: Deal with several faces
390         return faces[0]
391
392     def result(self):
393         """Returns the result data of this Feature."""
394         return self._feature.firstResult()