1 # Copyright (C) 2014-2023 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 perpendicular constraint is build for correponding line
160 self.__isPERP = [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 # Perpendicular for the lines which already have result
190 for i in range (0, 3):
193 aLine_A = ModelAPI.objectToFeature(aLinesList.object(i))
194 aLineResult_A = aLine_A.lastResult()
195 if aLineResult_A is None:
197 aLine_B = ModelAPI.objectToFeature(aLinesList.object(i+1))
198 aLineResult_B = aLine_B.lastResult()
199 if aLineResult_B is None:
201 aHVConstraint = self.__sketch.addFeature("SketchConstraintPerpendicular")
202 refattrA = aHVConstraint.refattr("ConstraintEntityA")
203 refattrA.setObject(aLine_A.lastResult())
204 refattrB = aHVConstraint.refattr("ConstraintEntityB")
205 refattrB.setObject(aLine_B.lastResult())
206 self.__isPERP[i] = True
208 def attributeChanged(self, theID):
209 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():
210 # Search the sketch containing this rectangle
212 aRefs = self.data().refsToMe();
214 aFeature = ModelAPI.objectToFeature(iter.owner())
215 if aFeature.getKind() == "Sketch":
216 self.__sketch = ModelAPI.featureToCompositeFeature(aFeature)
219 aLinesList = self.reflist(self.LINES_LIST_ID())
220 aNbLines = aLinesList.size()
222 # Create first line to be able to create a coincidence with selected point/feature
223 for i in range (0, 1):
224 aLine = self.__sketch.addFeature("SketchLine")
225 aLinesList.append(aLine)
227 aStartPoint = GeomDataAPI.geomDataAPI_Point2D(self.attribute(self.START_ID()))
228 aEndPoint = GeomDataAPI.geomDataAPI_Point2D(self.attribute(self.END_ID()))
229 aCenter = self.getPointByRef(self.attribute(self.CENTER_ID()), self.refattr(self.CENTER_REF_ID()))
230 aCorner = GeomDataAPI.geomDataAPI_Point2D(self.attribute(self.CORNER_ID()))
231 if (aStartPoint.isInitialized() and aEndPoint.isInitialized()) or (aCenter is not None and aCorner.isInitialized()):
234 self.updateStartPoint()
235 if theID == self.AUXILIARY_ID():
236 anAuxiliary = self.data().boolean(self.AUXILIARY_ID()).value()
237 aLinesList = self.reflist(self.LINES_LIST_ID())
238 aNbLines = aLinesList.size()
239 # Update coordinates of rectangle lines
240 for i in range (0, aNbLines):
241 aLine = ModelAPI.objectToFeature(aLinesList.object(i))
242 aLine.data().boolean("Auxiliary").setValue(anAuxiliary)
244 def getReferencePoint(self, theRef):
245 if theRef.isObject() and theRef.object() is not None:
246 feature = ModelAPI.ModelAPI_Feature.feature(theRef.object())
247 if feature.getKind() == "SketchPoint":
248 return feature.attribute("PointCoordinates")
253 def getPointByRef(self, thePoint, theRef):
255 if theRef.isInitialized():
256 refPnt = self.getReferencePoint(theRef)
257 if refPnt is not None:
259 if attr is None or not attr.isInitialized():
261 return GeomDataAPI.geomDataAPI_Point2D(attr).pnt()
263 def updateLines(self):
264 # Retrieving list of already created lines
265 aLinesList = self.reflist(self.LINES_LIST_ID())
266 aNbLines = min(aLinesList.size(), 4)
267 if self.string(self.RECTANGLE_TYPE_ID()).value() == self.RECTANGLE_CENTERED_ID():
268 aCenter = self.getPointByRef(self.attribute(self.CENTER_ID()), self.refattr(self.CENTER_REF_ID()))
269 aCorner = GeomDataAPI.geomDataAPI_Point2D(self.attribute(self.CORNER_ID()))
270 aStartX = 2.0 * aCenter.x() - aCorner.x()
271 aStartY = 2.0 * aCenter.y() - aCorner.y()
272 aX = [aStartX, aStartX, aCorner.x(), aCorner.x()]
273 aY = [aStartY, aCorner.y(), aCorner.y(), aStartY]
275 aStartPoint = GeomDataAPI.geomDataAPI_Point2D(self.attribute(self.START_ID()))
276 aEndPoint = GeomDataAPI.geomDataAPI_Point2D(self.attribute(self.END_ID()))
277 aX = [aStartPoint.x(), aStartPoint.x(), aEndPoint.x(), aEndPoint.x()]
278 aY = [aStartPoint.y(), aEndPoint.y(), aEndPoint.y(), aStartPoint.y()]
279 anAuxiliary = self.data().boolean(self.AUXILIARY_ID()).value()
281 # do not recalculate the rectrangle after each update
283 for i in range (0, aLinesList.size()):
284 wasBlocked.append(aLinesList.object(i).data().blockSendAttributeUpdated(True))
286 # Update coordinates of rectangle lines
287 for i in range (0, aNbLines):
288 aLine = ModelAPI.objectToFeature(aLinesList.object(i))
289 aLineStart = GeomDataAPI.geomDataAPI_Point2D(aLine.attribute("StartPoint"))
290 aLineEnd = GeomDataAPI.geomDataAPI_Point2D(aLine.attribute("EndPoint"))
291 aLineStart.setValue(aX[i-1], aY[i-1])
292 aLineEnd.setValue(aX[i], aY[i])
293 aLine.data().boolean("Auxiliary").setValue(anAuxiliary)
295 # Update auxiliary diagonals
296 if self.string(self.RECTANGLE_TYPE_ID()).value() == self.RECTANGLE_CENTERED_ID():
297 for i in range (aNbLines, aLinesList.size()):
298 aLine = ModelAPI.objectToFeature(aLinesList.object(i))
299 aLineStart = GeomDataAPI.geomDataAPI_Point2D(aLine.attribute("StartPoint"))
300 aLineEnd = GeomDataAPI.geomDataAPI_Point2D(aLine.attribute("EndPoint"))
301 aLineStart.setValue(aX[i-aNbLines-1], aY[i-aNbLines-1])
302 aLineEnd.setValue(aX[i-aNbLines+1], aY[i-aNbLines+1])
303 aLine.data().boolean("Auxiliary").setValue(True)
305 # update the rectangle
306 for i in range (0, aLinesList.size()):
307 aLinesList.object(i).data().blockSendAttributeUpdated(wasBlocked[i], True)
309 def updateStartPoint(self):
310 # Retrieving list of already created lines
311 aLinesList = self.reflist(self.LINES_LIST_ID())
312 aNbLines = aLinesList.size()
314 aStartPoint = GeomDataAPI.geomDataAPI_Point2D(self.attribute(self.START_ID()))
315 if aStartPoint.isInitialized:
319 aCenter = self.getPointByRef(self.attribute(self.CENTER_ID()), self.refattr(self.CENTER_REF_ID()))
323 # Update coordinates of rectangle lines
324 for i in range (0, aNbLines):
325 aLine = ModelAPI.objectToFeature(aLinesList.object(i))
326 aLineStart = GeomDataAPI.geomDataAPI_Point2D(aLine.attribute("EndPoint"))
327 aLineStart.setValue(aX, aY)