1 # Author: Daniel Brunier-Coulin with contribution by Mikhail Ponikarov
2 # finalized by Renaud Nedelec and Sergey Pokhodenko
3 # Copyright (C) 2014-20xx CEA/DEN, EDF R&D
5 """Sketch Feature Interface
7 This interface allows to add a Sketch
9 The created sketch object provides all the needed methods
10 for sketch modification and constraint edition.
13 from ModelAPI import modelAPI_ResultConstruction, featureToCompositeFeature
14 from GeomDataAPI import geomDataAPI_Point, geomDataAPI_Dir
15 from GeomAlgoAPI import GeomAlgoAPI_SketchBuilder, ShapeList
17 from model.sketcher.point import Point
18 from model.sketcher.line import Line
19 from model.sketcher.circle import Circle
20 from model.sketcher.arc import Arc
21 from model.sketcher.mirror import Mirror
22 from model.roots import Interface
23 from model.tools import Selection
26 def addSketch(doc, plane):
27 """Add a Sketch feature to the Part or PartSet and return an interface
30 A Sketch object is instanciated with a feature as input parameter
31 it provides an interface for manipulation of the feature data.
33 :return: interface on the feature
35 feature = featureToCompositeFeature(doc.addFeature("Sketch"))
36 return Sketch(feature, plane)
38 class Sketch(Interface):
39 """Interface class for Sketch feature."""
40 def __init__(self, feature, *args):
41 """Initialize a 2D Sketch on the given plane.
43 The plane can be defined either by:
44 - a 3D axis system (geom.Ax3),
45 - an existing face identified by its topological name.
47 Interface.__init__(self, feature)
48 assert(self._feature.getKind() == "Sketch")
50 self._origin = geomDataAPI_Point(
51 self._feature.data().attribute("Origin")
53 self._dir_x = geomDataAPI_Dir(
54 self._feature.data().attribute("DirX")
56 self._norm = geomDataAPI_Dir(
57 self._feature.data().attribute("Norm")
59 self._external = self._feature.data().selection("External")
61 # If no arguments are given the attributes of the feature
65 if isinstance(plane, str):
66 self.__sketchOnFace(plane)
68 self.__sketchOnPlane(plane)
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())
79 def __sketchOnFace(self, name):
80 """Initialize the sketch on a face given by its name."""
81 self._external.selectSubShape("FACE", name)
83 #-------------------------------------------------------------
85 # Creation of Geometries
87 #-------------------------------------------------------------
89 def addPoint(self, *args):
90 """Add a point to this Sketch."""
92 raise TypeError("No arguments given")
93 point_feature = self._feature.addFeature("SketchPoint")
94 return Point(point_feature, *args)
96 def addLine(self, *args):
97 """Add a line to this Sketch."""
99 raise TypeError("No arguments given")
100 line_feature = self._feature.addFeature("SketchLine")
101 line_interface = Line(line_feature, *args)
102 # if the line is created by name add a rigid constraint
103 # to the created line
104 if len(args) == 1 and isinstance(args[0], str):
105 constraint = self._feature.addFeature("SketchConstraintRigid")
106 constraint.refattr("ConstraintEntityA").setObject(
107 line_feature.firstResult()
109 return line_interface
111 def addCircle(self, *args):
112 """Add a circle to this Sketch."""
114 raise TypeError("No arguments given")
115 circle_feature = self._feature.addFeature("SketchCircle")
116 return Circle(circle_feature, *args)
118 def addArc(self, *args):
119 """Add an arc to the sketch.
121 :param sequence args: A sequence of arguments that can be:
123 * The center, start and end points
124 * The center, start and end points coordinates
126 :rtype: :class:`model.sketcher.Arc`
127 :raises TypeError: if no argument is provided
130 raise TypeError("No arguments given")
131 arc_feature = self._feature.addFeature("SketchArc")
132 return Arc(arc_feature, *args)
134 #-------------------------------------------------------------
136 # Creation of Geometrical and Dimensional Constraints
138 #-------------------------------------------------------------
140 def setCoincident(self, p1, p2):
141 """Set coincident the two given points and add the corresponding
142 constraint to this Sketch."""
143 # assert(p1 and p2) NOTE : if an argument is missing python
144 # will raise TypeError by itself.
145 # It seems better to check only that provided arguments are not
147 if p1 is None or p2 is None:
148 raise TypeError("NoneType argument given")
149 constraint = self._feature.addFeature("SketchConstraintCoincidence")
150 constraint.data().refattr("ConstraintEntityA").setAttr(p1)
151 constraint.data().refattr("ConstraintEntityB").setAttr(p2)
155 def setParallel(self, l1, l2):
156 """Set parallel the two given lines and add the corresponding
157 constraint to this Sketch."""
158 if l1 is None or l2 is None:
159 raise TypeError("NoneType argument given")
160 constraint = self._feature.addFeature("SketchConstraintParallel")
161 constraint.data().refattr("ConstraintEntityA").setObject(l1)
162 constraint.data().refattr("ConstraintEntityB").setObject(l2)
166 def setPerpendicular(self, l1, l2):
167 """Set perpendicular the two given lines and add the corresponding
168 constraint to this Sketch."""
169 if l1 is None or l2 is None:
170 raise TypeError("NoneType argument given")
171 constraint = self._feature.addFeature("SketchConstraintPerpendicular")
172 constraint.data().refattr("ConstraintEntityA").setObject(l1)
173 constraint.data().refattr("ConstraintEntityB").setObject(l2)
177 def setHorizontal(self, line):
178 """Set horizontal the given line and add the corresponding
179 constraint to this Sketch."""
181 raise TypeError("NoneType argument given")
182 constraint = self._feature.addFeature("SketchConstraintHorizontal")
183 constraint.data().refattr("ConstraintEntityA").setObject(line)
187 def setVertical(self, line):
188 """Set vertical the given line and add the corresponding
189 constraint to this Sketch."""
191 raise TypeError("NoneType argument given")
192 constraint = self._feature.addFeature("SketchConstraintVertical")
193 constraint.data().refattr("ConstraintEntityA").setObject(line)
197 def setDistance(self, point, line, length):
198 """Set the distance between the given point and line, and add
199 the corresponding constraint to this Sketch."""
200 if point is None or line is None:
201 raise TypeError("NoneType argument given")
202 constraint = self._feature.addFeature("SketchConstraintDistance")
203 if isinstance(line, basestring):
204 # Add the edge identified by the given topological name
206 line = self.addLine(line).result()
207 constraint.data().refattr("ConstraintEntityA").setAttr(point)
208 constraint.data().refattr("ConstraintEntityB").setObject(line)
209 constraint.data().real("ConstraintValue").setValue(length)
213 def setLength(self, line, length):
214 """Set the length of the given line and add the corresponding
215 constraint to this Sketch."""
217 raise TypeError("NoneType argument given")
218 constraint = self._feature.addFeature("SketchConstraintLength")
219 constraint.data().refattr("ConstraintEntityA").setObject(line)
220 constraint.data().real("ConstraintValue").setValue(length)
224 def setRadius(self, circle, radius):
225 """Set the radius of the given circle and add the corresponding
226 constraint to this Sketch."""
227 constraint = self._feature.addFeature("SketchConstraintRadius")
228 constraint.data().refattr("ConstraintEntityA").setObject(circle)
229 constraint.data().real("ConstraintValue").setValue(radius)
233 def setEqual(self, object_1, object_2):
234 """Set the radii of two circles or the length of two lines equal.
236 The corresponding constraint is added to the sketch"""
237 constraint = self._feature.addFeature("SketchConstraintEqual")
238 constraint.data().refattr("ConstraintEntityA").setObject(object_1)
239 constraint.data().refattr("ConstraintEntityB").setObject(object_2)
243 def setAngle(self, line_1, line_2, angle):
244 """Set the angle between the given 2 lines and add the corresponding
245 constraint to the sketch."""
246 constraint = self._feature.addFeature("SketchConstraintAngle")
247 constraint.data().refattr("ConstraintEntityA").setObject(line_1)
248 constraint.data().refattr("ConstraintEntityB").setObject(line_2)
249 constraint.data().real("ConstraintValue").setValue(angle)
253 def setTangent(self, object_1, object_2):
254 """Set a tangential continuity between two objects
255 at their coincidence point."""
256 if object_1 is None or object_2 is None:
257 raise TypeError("NoneType argument given")
258 constraint = self._feature.addFeature("SketchConstraintTangent")
259 constraint.data().refattr("ConstraintEntityA").setObject(object_1)
260 constraint.data().refattr("ConstraintEntityB").setObject(object_2)
264 def setFillet(self, line_1, line_2, radius):
265 """Set a fillet constraint between the 2 given lines with the given
267 constraint = self._feature.addFeature("SketchConstraintFillet")
268 constraint.data().refattr("ConstraintEntityA").setObject(line_1)
269 constraint.data().reflist("ConstraintEntityB").clear()
270 constraint.data().reflist("ConstraintEntityB").append(line_2)
274 def setRigid(self, object_):
275 """Set a rigid constraint on a given object."""
276 constraint = self._feature.addFeature("SketchConstraintRigid")
277 constraint.data().refattr("ConstraintEntityA").setObject(object_)
281 #-------------------------------------------------------------
283 # Transformation constraints
285 #-------------------------------------------------------------
287 def addMirror(self, mirror_line, sketch_objects):
288 """Add a mirror transformation of the given objects to the sketch.
290 This transformation is a constraint.
292 :return: interface to the constraint
293 :rtype: Mirror object
295 mirror_constraint = self._feature.addFeature("SketchConstraintMirror")
296 mirror_interface = Mirror(mirror_constraint, mirror_line, sketch_objects)
298 return mirror_interface
301 #-------------------------------------------------------------
303 # Edition of Dimensional Constraints
305 #-------------------------------------------------------------
307 def setValue(self, constraint, value):
308 """Modify the value of the given dimensional constraint."""
309 constraint.data().real("ConstraintValue").setValue(value)
311 #-------------------------------------------------------------
313 # Macro functions combining geometry creation and constraints
315 #-------------------------------------------------------------
317 def addPolyline(self, *coords):
318 """Add a poly-line to this Sketch.
320 The end of consecutive segments are defined as coincident.
325 line_1 = self.addLine(c0, c1)
326 polyline.append(line_1)
327 # Adding and connecting next lines
328 for c2 in coords[2:]:
329 line_2 = self.addLine(c1, c2)
330 self.setCoincident(line_1.endPointData(), line_2.startPointData())
331 polyline.append(line_2)
336 def addPolygon(self, *coords):
337 """Add a polygon to this Sketch.
339 The end of consecutive segments are defined as coincident.
341 pg = self.addPolyline(*coords)
342 # Closing the poly-line supposed being defined by at least 3 points
344 cn = coords[len(coords) - 1]
345 ln = self.addLine(cn, c0)
347 pg[len(coords) - 2].endPointData(), ln.startPointData()
350 ln.endPointData(), pg[0].startPointData()
355 #-------------------------------------------------------------
359 #-------------------------------------------------------------
361 def selectFace(self, *args):
362 """Select the geometrical entities of this Sketch on which
363 the result Face must be built.
365 When no entity is given, the face is based on all existing
366 geometry of this Sketch.
369 wire = modelAPI_ResultConstruction(
370 self._feature.firstResult()
373 wire = args[0].shape()
375 raise Exception("not yet implemented")
376 # TODO: simple version now, should be a list of selected faces
377 return [Selection(self.result(), self.buildShape(wire))]
379 def buildShape(self, wire):
380 """Build the result Shape of this Sketch according to the
381 selected geometrical entities."""
382 o = self._origin.pnt()
383 dx = self._dir_x.dir()
386 # The faces are kept otherwise they are destroyed at exit
388 GeomAlgoAPI_SketchBuilder.createFaces(o, dx, n, wire, faces)
389 # TODO: Deal with several faces
393 """Returns the result data of this Feature."""
394 return self._feature.firstResult()