Salome HOME
Merge branch 'python_parametric_api' of https://git.salome-platform.org/git/modules...
[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         assert(self._origin)
54         assert(self._dir_x)
55         assert(self._norm)
56         assert(self._external)
57
58         # If no arguments are given the attributes of the feature 
59         # are not Initialized
60         if args is not None:
61             plane = args[0]
62             if isinstance(plane, str):
63                 self.__sketchOnFace(plane)
64             else:
65                 self.__sketchOnPlane(plane)
66
67     def __sketchOnPlane(self, plane):
68         """Create the sketch on a plane."""
69         origin = plane.location()
70         normal = plane.direction()
71         x_direction = plane.xDirection()
72         self._origin.setValue(origin.x(), origin.y(), origin.z())
73         self._norm.setValue(normal.x(), normal.y(), normal.z())
74         self._dir_x.setValue(x_direction.x(), x_direction.y(), x_direction.z())
75
76     def __sketchOnFace(self, name):
77         """Initialize the sketch on a face given by its name."""
78         self._external.selectSubShape("FACE", name)
79
80     #-------------------------------------------------------------
81     #
82     # Creation of Geometries
83     #
84     #-------------------------------------------------------------
85
86     def addPoint(self, *args):
87         """Add a point to this Sketch."""
88         point_feature = self._feature.addFeature("SketchPoint")
89         return Point(point_feature, *args)
90
91     def addLine(self, *args):
92         """Add a line to this Sketch."""
93         line_feature = self._feature.addFeature("SketchLine")
94         line_interface = Line(line_feature, *args)
95         # if the line is created by name add a rigid constraint
96         # to the created line
97         if len(args) == 1 and isinstance(args[0], str):
98             constraint = self._feature.addFeature("SketchConstraintRigid")
99             constraint.refattr("ConstraintEntityA").setObject(
100                 line_feature.firstResult()
101                 )
102         return line_interface
103
104     def addCircle(self, *args):
105         """Add a circle to this Sketch."""
106         circle_feature = self._feature.addFeature("SketchCircle")
107         return Circle(circle_feature, *args)
108
109     def addArc(self, *args):
110         """Add an arc to this Sketch."""
111         arc_feature = self._feature.addFeature("SketchArc")
112         return Arc(arc_feature, *args)
113
114     #-------------------------------------------------------------
115     #
116     # Creation of Geometrical and Dimensional Constraints
117     #
118     #-------------------------------------------------------------
119
120     def setCoincident(self, p1, p2):
121         """Set coincident the two given points and add the corresponding
122         constraint to this Sketch."""
123         assert(p1 and p2)
124         constraint = self._feature.addFeature("SketchConstraintCoincidence")
125         constraint.data().refattr("ConstraintEntityA").setAttr(p1)
126         constraint.data().refattr("ConstraintEntityB").setAttr(p2)
127         self.execute()
128         return constraint
129
130     def setParallel(self, l1, l2):
131         """Set parallel the two given lines and add the corresponding
132         constraint to this Sketch."""
133         assert(l1 and l2)
134         constraint = self._feature.addFeature("SketchConstraintParallel")
135         constraint.data().refattr("ConstraintEntityA").setObject(l1)
136         constraint.data().refattr("ConstraintEntityB").setObject(l2)
137         self.execute()
138         return constraint
139
140     def setPerpendicular(self, l1, l2):
141         """Set perpendicular the two given lines and add the corresponding
142         constraint to this Sketch."""
143         assert(l1 and l2)
144         constraint = self._feature.addFeature("SketchConstraintPerpendicular")
145         constraint.data().refattr("ConstraintEntityA").setObject(l1)
146         constraint.data().refattr("ConstraintEntityB").setObject(l2)
147         self.execute()
148         return constraint
149
150     def setHorizontal(self, line):
151         """Set horizontal the given line and add the corresponding
152         constraint to this Sketch."""
153         constraint = self._feature.addFeature("SketchConstraintHorizontal")
154         constraint.data().refattr("ConstraintEntityA").setObject(line)
155         self.execute()
156         return constraint
157
158     def setVertical(self, line):
159         """Set vertical the given line and add the corresponding
160         constraint to this Sketch."""
161         constraint = self._feature.addFeature("SketchConstraintVertical")
162         constraint.data().refattr("ConstraintEntityA").setObject(line)
163         self.execute()
164         return constraint
165
166     def setDistance(self, point, line, length):
167         """Set the distance between the given point and line, and add
168         the corresponding constraint to this Sketch."""
169         assert(point and line)
170         constraint = self._feature.addFeature("SketchConstraintDistance")
171         if isinstance(line, basestring):
172             # Add the edge identified by the given topological name
173             # to this Sketch
174             line = self.addLine(line).result()
175             assert(line)
176         constraint.data().refattr("ConstraintEntityA").setAttr(point)
177         constraint.data().refattr("ConstraintEntityB").setObject(line)
178         constraint.data().real("ConstraintValue").setValue(length)
179         self.execute()
180         return constraint
181
182     def setLength(self, line, length):
183         """Set the length of the given line and add the corresponding
184         constraint to this Sketch."""
185         assert(line)
186         constraint = self._feature.addFeature("SketchConstraintLength")
187         constraint.data().refattr("ConstraintEntityA").setObject(line)
188         constraint.data().real("ConstraintValue").setValue(length)
189         self.execute()
190         return constraint
191
192     def setRadius(self, circle, radius):
193         """Set the radius of the given circle and add the corresponding
194         constraint to this Sketch."""
195         constraint = self._feature.addFeature("SketchConstraintRadius")
196         constraint.data().refattr("ConstraintEntityA").setObject(circle)
197         constraint.data().real("ConstraintValue").setValue(radius)
198         self.execute()
199         return constraint
200
201     def setEqual(self, object_1, object_2):
202         """Set the radii of two circles or the length of two lines equal.
203
204         The corresponding constraint is added to the sketch"""
205         constraint = self._feature.addFeature("SketchConstraintEqual")
206         constraint.data().refattr("ConstraintEntityA").setObject(object_1)
207         constraint.data().refattr("ConstraintEntityB").setObject(object_2)
208         self.execute()
209         return constraint
210
211     def setAngle(self, line_1, line_2, angle):
212         """Set the angle between the given 2 lines and add the corresponding
213         constraint to the sketch."""
214         constraint = self._feature.addFeature("SketchConstraintAngle")
215         constraint.data().refattr("ConstraintEntityA").setObject(line_1)
216         constraint.data().refattr("ConstraintEntityB").setObject(line_2)
217         constraint.data().real("ConstraintValue").setValue(angle)
218         self.execute()
219         return constraint
220
221     def setTangent(self, object_1, object_2):
222         """Set a tangential continuity between two objects
223         at their coincidence point."""
224         constraint = self._feature.addFeature("SketchConstraintTangent")
225         constraint.data().refattr("ConstraintEntityA").setObject(object_1)
226         constraint.data().refattr("ConstraintEntityB").setObject(object_2)
227         self.execute()
228         return constraint
229
230     def setFillet(self, line_1, line_2, radius):
231         """Set a fillet constraint between the 3 given lines with the given
232         filleting radius."""
233         constraint = self._feature.addFeature("SketchConstraintFillet")
234         constraint.data().refattr("ConstraintEntityA").setObject(line_1)
235         constraint.data().refattr("ConstraintEntityB").setObject(line_2)
236         constraint.data().real("ConstraintValue").setValue(radius)
237         self.execute()
238         return constraint
239
240     #-------------------------------------------------------------
241     #
242     # Edition of Dimensional Constraints
243     #
244     #-------------------------------------------------------------
245
246     def setValue(self, constraint, value):
247         """Modify the value of the given dimensional constraint."""
248         constraint.data().real("ConstraintValue").setValue(value)
249
250     #-------------------------------------------------------------
251     #
252     # Macro functions combining geometry creation and constraints
253     #
254     #-------------------------------------------------------------
255
256     def addPolyline(self, *coords):
257         """Add a poly-line to this Sketch.
258
259         The end of consecutive segments are defined as coincident.
260         """
261         c0 = coords[0]
262         c1 = coords[1]
263         polyline = []
264         line_1 = self.addLine(c0, c1)
265         polyline.append(line_1)
266         # Adding and connecting next lines
267         for c2 in coords[2:]:
268             line_2 = self.addLine(c1, c2)
269             self.setCoincident(line_1.endPointData(), line_2.startPointData())
270             polyline.append(line_2)
271             c1 = c2
272             line_1 = line_2
273         return polyline
274
275     def addPolygon(self, *coords):
276         """Add a polygon to this Sketch.
277
278         The end of consecutive segments are defined as coincident.
279         """
280         pg = self.addPolyline(*coords)
281         # Closing the poly-line supposed being defined by at least 3 points
282         c0 = coords[0]
283         cn = coords[len(coords) - 1]
284         ln = self.addLine(cn, c0)
285         self.setCoincident(
286             pg[len(coords) - 2].endPointData(), ln.startPointData()
287             )
288         self.setCoincident(
289             ln.endPointData(), pg[0].startPointData()
290             )
291         pg.append(ln)
292         return pg
293
294     #-------------------------------------------------------------
295     #
296     # Getters
297     #
298     #-------------------------------------------------------------
299
300     def selectFace(self, *args):
301         """Select the geometrical entities of this Sketch on which
302         the result Face must be built.
303
304         When no entity is given, the face is based on all existing
305         geometry of this Sketch.
306         """
307         if len(args) == 0:
308             wire = modelAPI_ResultConstruction(
309                 self._feature.firstResult()
310                 ).shape()
311         elif len(args) == 1:
312             wire = args[0].shape()
313         else:
314             raise Exception("not yet implemented")
315         # TODO: simple version now, should be a list of selected faces
316         return [Selection(self.result(), self.buildShape(wire))]
317
318     def buildShape(self, wire):
319         """Build the result Shape of this Sketch according to the
320         selected geometrical entities."""
321         o = self._origin.pnt()
322         dx = self._dir_x.dir()
323         n = self._norm.dir()
324
325         # The faces are kept otherwise they are destroyed at exit
326         faces = ShapeList()
327         GeomAlgoAPI_SketchBuilder.createFaces(o, dx, n, wire, faces)
328         # TODO: Deal with several faces
329         return faces[0]
330
331     def result(self):
332         """Returns the result data of this Feature."""
333         return self._feature.firstResult()