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