1 # Copyright (C) 2014-2022 CEA/DEN, EDF R&D
3 # This library is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU Lesser General Public
5 # License as published by the Free Software Foundation; either
6 # version 2.1 of the License, or (at your option) any later version.
8 # This library is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 # Lesser General Public License for more details.
13 # You should have received a copy of the GNU Lesser General Public
14 # License along with this library; if not, write to the Free Software
15 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 Macro-feature to produce rectangle in the sketcher
25 from salome.shaper import model
29 class SketchPlugin_Rectangle(model.Feature):
31 Implementation of rectangle creation.
33 It produced 2 horizontal lines and 2 vertical lines connected by coincidence constraints
39 """x.__init__(...) initializes x; see x.__class__.__doc__ for signature"""
40 model.Feature.__init__(self)
44 """Rectangle feature kind."""
45 return "SketchRectangle"
49 """Returns ID of first corner."""
50 return "RectStartPoint"
54 """Returns ID of second corner."""
59 """Returns whether the rectangle is accessory."""
64 """Returns ID of list containing lines created."""
65 return "RectangleList"
68 def RECTANGLE_TYPE_ID():
69 """Returns ID of type of rectangle creation (by corners or by center and corner)."""
70 return "RectangleType"
73 def RECTANGLE_BY_CORNERS_ID():
74 """Returns ID of creation type by opposite corners."""
75 return "RectangleTypeByCorners"
78 def RECTANGLE_CENTERED_ID():
79 """Returns ID of creation type by center point and a corner."""
80 return "RectangleTypeCentered"
84 """Returns ID of center point."""
85 return "RectCenterPoint"
89 """Returns ID of the reference to the center point."""
90 return "RectCenterPointRef"
94 """Returns ID of a corner."""
95 return "RectCornerPoint"
99 """Override Feature.getKind()"""
100 return SketchPlugin_Rectangle.ID()
103 # Initialization of the rectangle
105 def initAttributes(self):
106 """Override Feature.initAttributes()"""
107 # Flag whether the rectangle is accessory
108 self.data().addAttribute(self.AUXILIARY_ID(), ModelAPI.ModelAPI_AttributeBoolean_typeId())
109 # Creating corners of the rectangle
110 self.data().addAttribute(self.START_ID(), GeomDataAPI.GeomDataAPI_Point2D_typeId())
111 self.data().addAttribute(self.END_ID(), GeomDataAPI.GeomDataAPI_Point2D_typeId())
112 # Creating list to store lines
113 self.data().addAttribute(self.LINES_LIST_ID(), ModelAPI.ModelAPI_AttributeRefList_typeId())
114 ModelAPI.ModelAPI_Session.get().validators().registerNotObligatory(self.getKind(), self.LINES_LIST_ID())
116 self.data().addAttribute(self.RECTANGLE_TYPE_ID(), ModelAPI.ModelAPI_AttributeString_typeId())
117 # Center and corner of the rectangle
118 self.data().addAttribute(self.CENTER_ID(), GeomDataAPI.GeomDataAPI_Point2D_typeId())
119 self.data().addAttribute(self.CORNER_ID(), GeomDataAPI.GeomDataAPI_Point2D_typeId())
121 self.data().addAttribute(self.CENTER_REF_ID(), ModelAPI.ModelAPI_AttributeRefAttr_typeId())
122 ModelAPI.ModelAPI_Session.get().validators().registerNotObligatory(self.getKind(), self.CENTER_REF_ID())
126 Override Feature.isMacro().
127 Rectangle feature is macro: removes itself on the creation transaction finish.
131 # Edition of the rectangle
134 # Retrieving list of already created lines
135 aLinesList = self.reflist(self.LINES_LIST_ID())
136 aNbLines = aLinesList.size()
138 # Create 1-4 lines to compose the rectangle
139 for i in range (0, 3):
140 aLine = self.__sketch.addFeature("SketchLine")
141 aLinesList.append(aLine)
143 aNbLines = aLinesList.size()
145 # Create constraints to keep the rectangle
146 for i in range (0, aNbLines):
147 aLine = ModelAPI.objectToFeature(aLinesList.object(i))
148 # connect neighbor lines by coincidence
152 aPrevLine = ModelAPI.objectToFeature(aLinesList.object(iPrev))
153 aCoincidence = self.__sketch.addFeature("SketchConstraintCoincidence")
154 aRefAttrA = aCoincidence.refattr("ConstraintEntityA")
155 aRefAttrB = aCoincidence.refattr("ConstraintEntityB")
156 aRefAttrA.setAttr(aPrevLine.attribute("EndPoint"))
157 aRefAttrB.setAttr(aLine.attribute("StartPoint"))
158 aStartPoints.append(aLine.attribute("StartPoint"))
159 # Flags which show horizontal or vertical constraint is build for correponding line
160 self.__isHV = [False, False, False, False]
161 # Update coordinates of created lines
163 # Create auxiliary diagonals in case of centered rectangle
164 if self.string(self.RECTANGLE_TYPE_ID()).value() == self.RECTANGLE_CENTERED_ID():
165 aDiag1 = self.__sketch.addFeature("SketchLine")
166 aLinesList.append(aDiag1)
167 aDiag2 = self.__sketch.addFeature("SketchLine")
168 aLinesList.append(aDiag2)
169 # coincidences in corners
170 aPoints = [aDiag1.attribute("StartPoint"), aDiag2.attribute("StartPoint"),
171 aDiag1.attribute("EndPoint"), aDiag2.attribute("EndPoint")]
172 for i in range (0, len(aPoints)):
173 aCoincidence = self.__sketch.addFeature("SketchConstraintCoincidence")
174 aRefAttrA = aCoincidence.refattr("ConstraintEntityA")
175 aRefAttrB = aCoincidence.refattr("ConstraintEntityB")
176 aRefAttrA.setAttr(aStartPoints[i])
177 aRefAttrB.setAttr(aPoints[i])
178 # Update coordinates of created lines
182 # coincidences between center point and diagonals
183 refPnt = self.getReferencePoint(self.refattr(self.CENTER_REF_ID()))
184 if refPnt is not None:
185 for line in [aDiag1.lastResult(), aDiag2.lastResult()]:
186 aCoincidence = self.__sketch.addFeature("SketchConstraintCoincidence")
187 aCoincidence.refattr("ConstraintEntityA").setAttr(refPnt)
188 aCoincidence.refattr("ConstraintEntityB").setObject(line)
189 # Add horizontal and vertical constraint for the lines which already have result
190 for i in range (0, 4):
193 aLine = ModelAPI.objectToFeature(aLinesList.object(i))
194 aLineResult = aLine.lastResult()
195 if aLineResult is None:
197 aHVName = "SketchConstraintHorizontal"
199 aHVName = "SketchConstraintVertical"
200 aHVConstraint = self.__sketch.addFeature(aHVName)
201 aRefAttrA = aHVConstraint.refattr("ConstraintEntityA")
202 aRefAttrA.setObject(aLine.lastResult())
203 self.__isHV[i] = True
205 def attributeChanged(self, theID):
206 if theID == self.START_ID() or theID == self.END_ID() or theID == self.CENTER_ID() or theID == self.CENTER_REF_ID() or theID == self.CORNER_ID():
207 # Search the sketch containing this rectangle
209 aRefs = self.data().refsToMe();
211 aFeature = ModelAPI.objectToFeature(iter.owner())
212 if aFeature.getKind() == "Sketch":
213 self.__sketch = ModelAPI.featureToCompositeFeature(aFeature)
216 aLinesList = self.reflist(self.LINES_LIST_ID())
217 aNbLines = aLinesList.size()
219 # Create first line to be able to create a coincidence with selected point/feature
220 for i in range (0, 1):
221 aLine = self.__sketch.addFeature("SketchLine")
222 aLinesList.append(aLine)
224 aStartPoint = GeomDataAPI.geomDataAPI_Point2D(self.attribute(self.START_ID()))
225 aEndPoint = GeomDataAPI.geomDataAPI_Point2D(self.attribute(self.END_ID()))
226 aCenter = self.getPointByRef(self.attribute(self.CENTER_ID()), self.refattr(self.CENTER_REF_ID()))
227 aCorner = GeomDataAPI.geomDataAPI_Point2D(self.attribute(self.CORNER_ID()))
228 if (aStartPoint.isInitialized() and aEndPoint.isInitialized()) or (aCenter is not None and aCorner.isInitialized()):
231 self.updateStartPoint()
232 if theID == self.AUXILIARY_ID():
233 anAuxiliary = self.data().boolean(self.AUXILIARY_ID()).value()
234 aLinesList = self.reflist(self.LINES_LIST_ID())
235 aNbLines = aLinesList.size()
236 # Update coordinates of rectangle lines
237 for i in range (0, aNbLines):
238 aLine = ModelAPI.objectToFeature(aLinesList.object(i))
239 aLine.data().boolean("Auxiliary").setValue(anAuxiliary)
241 def getReferencePoint(self, theRef):
242 if theRef.isObject() and theRef.object() is not None:
243 feature = ModelAPI.ModelAPI_Feature.feature(theRef.object())
244 if feature.getKind() == "SketchPoint":
245 return feature.attribute("PointCoordinates")
250 def getPointByRef(self, thePoint, theRef):
252 if theRef.isInitialized():
253 refPnt = self.getReferencePoint(theRef)
254 if refPnt is not None:
256 if attr is None or not attr.isInitialized():
258 return GeomDataAPI.geomDataAPI_Point2D(attr).pnt()
260 def updateLines(self):
261 # Retrieving list of already created lines
262 aLinesList = self.reflist(self.LINES_LIST_ID())
263 aNbLines = min(aLinesList.size(), 4)
264 if self.string(self.RECTANGLE_TYPE_ID()).value() == self.RECTANGLE_CENTERED_ID():
265 aCenter = self.getPointByRef(self.attribute(self.CENTER_ID()), self.refattr(self.CENTER_REF_ID()))
266 aCorner = GeomDataAPI.geomDataAPI_Point2D(self.attribute(self.CORNER_ID()))
267 aStartX = 2.0 * aCenter.x() - aCorner.x()
268 aStartY = 2.0 * aCenter.y() - aCorner.y()
269 aX = [aStartX, aStartX, aCorner.x(), aCorner.x()]
270 aY = [aStartY, aCorner.y(), aCorner.y(), aStartY]
272 aStartPoint = GeomDataAPI.geomDataAPI_Point2D(self.attribute(self.START_ID()))
273 aEndPoint = GeomDataAPI.geomDataAPI_Point2D(self.attribute(self.END_ID()))
274 aX = [aStartPoint.x(), aStartPoint.x(), aEndPoint.x(), aEndPoint.x()]
275 aY = [aStartPoint.y(), aEndPoint.y(), aEndPoint.y(), aStartPoint.y()]
276 anAuxiliary = self.data().boolean(self.AUXILIARY_ID()).value()
278 # do not recalculate the rectrangle after each update
280 for i in range (0, aLinesList.size()):
281 wasBlocked.append(aLinesList.object(i).data().blockSendAttributeUpdated(True))
283 # Update coordinates of rectangle lines
284 for i in range (0, aNbLines):
285 aLine = ModelAPI.objectToFeature(aLinesList.object(i))
286 aLineStart = GeomDataAPI.geomDataAPI_Point2D(aLine.attribute("StartPoint"))
287 aLineEnd = GeomDataAPI.geomDataAPI_Point2D(aLine.attribute("EndPoint"))
288 aLineStart.setValue(aX[i-1], aY[i-1])
289 aLineEnd.setValue(aX[i], aY[i])
290 aLine.data().boolean("Auxiliary").setValue(anAuxiliary)
292 # Update auxiliary diagonals
293 if self.string(self.RECTANGLE_TYPE_ID()).value() == self.RECTANGLE_CENTERED_ID():
294 for i in range (aNbLines, aLinesList.size()):
295 aLine = ModelAPI.objectToFeature(aLinesList.object(i))
296 aLineStart = GeomDataAPI.geomDataAPI_Point2D(aLine.attribute("StartPoint"))
297 aLineEnd = GeomDataAPI.geomDataAPI_Point2D(aLine.attribute("EndPoint"))
298 aLineStart.setValue(aX[i-aNbLines-1], aY[i-aNbLines-1])
299 aLineEnd.setValue(aX[i-aNbLines+1], aY[i-aNbLines+1])
300 aLine.data().boolean("Auxiliary").setValue(True)
302 # update the rectangle
303 for i in range (0, aLinesList.size()):
304 aLinesList.object(i).data().blockSendAttributeUpdated(wasBlocked[i], True)
306 def updateStartPoint(self):
307 # Retrieving list of already created lines
308 aLinesList = self.reflist(self.LINES_LIST_ID())
309 aNbLines = aLinesList.size()
311 aStartPoint = GeomDataAPI.geomDataAPI_Point2D(self.attribute(self.START_ID()))
312 if aStartPoint.isInitialized:
316 aCenter = self.getPointByRef(self.attribute(self.CENTER_ID()), self.refattr(self.CENTER_REF_ID()))
320 # Update coordinates of rectangle lines
321 for i in range (0, aNbLines):
322 aLine = ModelAPI.objectToFeature(aLinesList.object(i))
323 aLineStart = GeomDataAPI.geomDataAPI_Point2D(aLine.attribute("EndPoint"))
324 aLineStart.setValue(aX, aY)