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