1# Copyright (C) 2014-2026 CEA, EDF
2#
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.
7#
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.
12#
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
16#
17# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18#
19
20"""
21Macro-feature to produce rectangle in the sketcher
22Author: Artem ZHIDKOV
23"""
24
25from salome.shaper import model
26import ModelAPI
27import GeomDataAPI
28
29class SketchPlugin_Rectangle(model.Feature):
30 """
31 Implementation of rectangle creation.
32
33 It produced 2 horizontal lines and 2 vertical lines connected by coincidence constraints
34 """
35
36# Initializations
37
38 def __init__(self):
39 """x.__init__(...) initializes x; see x.__class__.__doc__ for signature"""
40 model.Feature.__init__(self)
41
42 @staticmethod
43 def ID():
44 """Rectangle feature kind."""
45 return "SketchRectangle"
46
47 @staticmethod
48 def START_ID():
49 """Returns ID of first corner."""
50 return "RectStartPoint"
51
52 @staticmethod
53 def END_ID():
54 """Returns ID of second corner."""
55 return "RectEndPoint"
56
57 @staticmethod
58 def AUXILIARY_ID():
59 """Returns whether the rectangle is accessory."""
60 return "Auxiliary"
61
62 @staticmethod
63 def LINES_LIST_ID():
64 """Returns ID of list containing lines created."""
65 return "RectangleList"
66
67 def getKind(self):
68 """Override Feature.getKind()"""
69 return SketchPlugin_Rectangle.ID()
70
71
72# Initialization of the rectangle
73
74 def initAttributes(self):
75 """Override Feature.initAttributes()"""
76 # Flag whether the rectangle is accessory
77 self.data().addAttribute(self.AUXILIARY_ID(), ModelAPI.ModelAPI_AttributeBoolean.typeId())
78 # Creating corners of the rectangle
79 self.data().addAttribute(self.START_ID(), GeomDataAPI.GeomDataAPI_Point2D.typeId())
80 self.data().addAttribute(self.END_ID(), GeomDataAPI.GeomDataAPI_Point2D.typeId())
81 # Creating list to store lines
82 self.data().addAttribute(self.LINES_LIST_ID(), ModelAPI.ModelAPI_AttributeRefList.typeId())
83 ModelAPI.ModelAPI_Session.get().validators().registerNotObligatory(self.getKind(), self.LINES_LIST_ID())
84
85 def isMacro(self):
86 """
87 Override Feature.isMacro().
88 Rectangle feature is macro: removes itself on the creation transaction finish.
89 """
90 return True
91
92# Edition of the rectangle
93
94 def execute(self):
95 # Retrieving list of already created lines
96 aLinesList = self.reflist(self.LINES_LIST_ID())
97 aNbLines = aLinesList.size()
98 if aNbLines == 1:
99 # Create 1-4 lines to compose the rectangle
100 for i in range (0, 3):
101 aLine = self.__sketch.addFeature("SketchLine")
102 aLinesList.append(aLine)
103 self.updateLines()
104 aNbLines = aLinesList.size()
105 # Create constraints to keep the rectangle
106 for i in range (0, aNbLines):
107 aLine = ModelAPI.objectToFeature(aLinesList.object(i))
108 # connect neighbor lines by coincidence
109 iPrev = i - 1
110 if iPrev < 0:
111 iPrev = aNbLines - 1
112 aPrevLine = ModelAPI.objectToFeature(aLinesList.object(iPrev))
113 aCoincidence = self.__sketch.addFeature("SketchConstraintCoincidence")
114 aRefAttrA = aCoincidence.refattr("ConstraintEntityA")
115 aRefAttrB = aCoincidence.refattr("ConstraintEntityB")
116 aRefAttrA.setAttr(aPrevLine.attribute("EndPoint"))
117 aRefAttrB.setAttr(aLine.attribute("StartPoint"))
118 # Flags which show horizontal or vertical constraint is build for corresponding line
119 self.__isHV = [False, False, False, False]
120 # Update coordinates of created lines
121 self.updateLines()
122 # Add horizontal and vertical constraint for the lines which already have result
123 for i in range (0, aNbLines):
124 if self.__isHV[i]:
125 continue
126 aLine = ModelAPI.objectToFeature(aLinesList.object(i))
127 aLineResult = aLine.lastResult()
128 if aLineResult is None:
129 continue
130 aHVName = "SketchConstraintHorizontal"
131 if i % 2 == 1:
132 aHVName = "SketchConstraintVertical"
133 aHVConstraint = self.__sketch.addFeature(aHVName)
134 aRefAttrA = aHVConstraint.refattr("ConstraintEntityA")
135 aRefAttrA.setObject(aLine.lastResult())
136 self.__isHV[i] = True
137
138 def attributeChanged(self, theID):
139 if theID == self.START_ID() or theID == self.END_ID():
140 # Search the sketch containing this rectangle
141 self.__sketch = None
142 aRefs = self.data().refsToMe();
143 for iter in aRefs:
144 aFeature = ModelAPI.objectToFeature(iter.owner())
145 if aFeature.getKind() == "Sketch":
146 self.__sketch = ModelAPI.featureToCompositeFeature(aFeature)
147 break
148
149 aLinesList = self.reflist(self.LINES_LIST_ID())
150 aNbLines = aLinesList.size()
151 if aNbLines == 0:
152 # Create first line to be able to create a coincidence with selected point/feature
153 for i in range (0, 1):
154 aLine = self.__sketch.addFeature("SketchLine")
155 aLinesList.append(aLine)
156
157 aStartPoint = GeomDataAPI.geomDataAPI_Point2D(self.attribute(self.START_ID()))
158 aEndPoint = GeomDataAPI.geomDataAPI_Point2D(self.attribute(self.END_ID()))
159 if aStartPoint.isInitialized() and aEndPoint.isInitialized():
160 self.updateLines()
161 else:
162 self.updateStartPoint()
163 if theID == self.AUXILIARY_ID():
164 anAuxiliary = self.data().boolean(self.AUXILIARY_ID()).value()
165 aLinesList = self.reflist(self.LINES_LIST_ID())
166 aNbLines = aLinesList.size()
167 # Update coordinates of rectangle lines
168 for i in range (0, aNbLines):
169 aLine = ModelAPI.objectToFeature(aLinesList.object(i))
170 aLine.data().boolean("Auxiliary").setValue(anAuxiliary)
171
172
173 def updateLines(self):
174 # Retrieving list of already created lines
175 aLinesList = self.reflist(self.LINES_LIST_ID())
176 aNbLines = aLinesList.size()
177 aStartPoint = GeomDataAPI.geomDataAPI_Point2D(self.attribute(self.START_ID()))
178 aEndPoint = GeomDataAPI.geomDataAPI_Point2D(self.attribute(self.END_ID()))
179 aX = [aStartPoint.x(), aStartPoint.x(), aEndPoint.x(), aEndPoint.x()]
180 aY = [aStartPoint.y(), aEndPoint.y(), aEndPoint.y(), aStartPoint.y()]
181 anAuxiliary = self.data().boolean(self.AUXILIARY_ID()).value()
182
183 # Update coordinates of rectangle lines
184 for i in range (0, aNbLines):
185 aLine = ModelAPI.objectToFeature(aLinesList.object(i))
186 aLineStart = GeomDataAPI.geomDataAPI_Point2D(aLine.attribute("StartPoint"))
187 aLineEnd = GeomDataAPI.geomDataAPI_Point2D(aLine.attribute("EndPoint"))
188 aLineStart.setValue(aX[i-1], aY[i-1])
189 aLineEnd.setValue(aX[i], aY[i])
190 aLine.data().boolean("Auxiliary").setValue(anAuxiliary)
191
192 def updateStartPoint(self):
193 # Retrieving list of already created lines
194 aLinesList = self.reflist(self.LINES_LIST_ID())
195 aNbLines = aLinesList.size()
196
197 aStartPoint = GeomDataAPI.geomDataAPI_Point2D(self.attribute(self.START_ID()))
198 aX = aStartPoint.x()
199 aY = aStartPoint.y()
200
201 # Update coordinates of rectangle lines
202 for i in range (0, aNbLines):
203 aLine = ModelAPI.objectToFeature(aLinesList.object(i))
204 aLineStart = GeomDataAPI.geomDataAPI_Point2D(aLine.attribute("EndPoint"))
205 aLineStart.setValue(aX, aY)