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