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