Salome HOME
3a5acdd5af8c1e54e4c676041f1eab2350b6c236
[modules/shaper.git] / src / SketchPlugin / Test / TestConstraintCoincidenceEllipse.py
1 # Copyright (C) 2019-2024  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 """
21     Test constraint coincidence applied for ellipse and its sub-results
22 """
23
24 import unittest
25 import math
26
27 from salome.shaper import model
28
29 from GeomAPI import *
30 from SketchAPI import *
31
32 __updated__ = "2019-09-12"
33
34 class TestCoincidenceEllipse(unittest.TestCase):
35   def setUp(self):
36     axisStart = GeomAPI_Pnt2d(30., 60.)
37     axisEnd = GeomAPI_Pnt2d(80., 50.)
38     passedPoint = GeomAPI_Pnt2d(60., 60.)
39
40     model.begin()
41     self.myDocument = model.moduleDocument()
42     self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
43     macroEllipse = self.mySketch.addEllipse(axisStart, axisEnd, passedPoint, False)
44     self.myDOF = 5
45     self.myOrigin = self.mySketch.addPoint("Origin")
46     self.myOX = self.mySketch.addLine("OX")
47     model.do()
48     self.myEllipse = SketchAPI_Ellipse(model.lastSubFeature(self.mySketch, "SketchEllipse"))
49     self.myCenter = macroEllipse.center()
50     self.myFocus1 = macroEllipse.focus1()
51     self.myFocus2 = macroEllipse.focus2()
52     self.myMajorAxis = macroEllipse.majorAxis()
53     self.myMajorStart = macroEllipse.majorAxisStart()
54     self.myMajorEnd = macroEllipse.majorAxisEnd()
55     self.myMinorAxis = macroEllipse.minorAxis()
56     self.myMinorStart = macroEllipse.minorAxisStart()
57     self.myMinorEnd = macroEllipse.minorAxisEnd()
58     self.myExpectFailure = False
59     self.myNbCoindicences = 1
60
61   def tearDown(self):
62     model.end()
63     if self.myExpectFailure:
64       assert(self.mySketch.solverError() != ""), "PlaneGCS limitation: if you see this message, then PlaneGCS has solved the set of constraints correctly"
65       model.undo()
66     else:
67       self.checkDOF()
68       self.assertPoints(self.myCenter.coordinates(), self.myEllipse.center())
69       self.assertPoints(self.myFocus1.coordinates(), self.myEllipse.firstFocus())
70       self.assertPoints(self.myFocus2.coordinates(), self.myEllipse.secondFocus())
71       self.assertPoints(self.myMajorStart.coordinates(), self.myEllipse.majorAxisNegative())
72       self.assertPoints(self.myMajorEnd.coordinates(), self.myEllipse.majorAxisPositive())
73       self.assertPoints(self.myMajorAxis.startPoint(), self.myEllipse.majorAxisNegative())
74       self.assertPoints(self.myMajorAxis.endPoint(), self.myEllipse.majorAxisPositive())
75       self.assertPoints(self.myMinorStart.coordinates(), self.myEllipse.minorAxisNegative())
76       self.assertPoints(self.myMinorEnd.coordinates(), self.myEllipse.minorAxisPositive())
77       self.assertPoints(self.myMinorAxis.startPoint(), self.myEllipse.minorAxisNegative())
78       self.assertPoints(self.myMinorAxis.endPoint(), self.myEllipse.minorAxisPositive())
79       model.testNbSubFeatures(self.mySketch, "SketchPoint", 8)
80       model.testNbSubFeatures(self.mySketch, "SketchLine", 3)
81       model.testNbSubFeatures(self.mySketch, "SketchEllipse", 1)
82       model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidenceInternal", 11)
83       model.testNbSubFeatures(self.mySketch, "SketchConstraintCoincidence", self.myNbCoindicences)
84
85
86   def checkDOF(self):
87     self.assertEqual(model.dof(self.mySketch), self.myDOF)
88
89   def checkPointFixing(self, thePoint):
90     self.mySketch.setCoincident(thePoint, self.myOrigin.coordinates())
91     self.myDOF -= 2
92     model.do()
93     if not self.myExpectFailure:
94       self.assertPoints(thePoint, self.myOrigin.coordinates())
95       self.assertGreater(self.myEllipse.majorRadius().value(), 0.0)
96       self.assertGreater(self.myEllipse.minorRadius().value(), 0.0)
97
98   def assertPoints(self, thePoint1, thePoint2):
99     self.assertAlmostEqual(thePoint1.x(), thePoint2.x(), delta = 1.e-6)
100     self.assertAlmostEqual(thePoint1.y(), thePoint2.y(), delta = 1.e-6)
101
102   def checkPointOnAxis(self, thePoint):
103     self.mySketch.setCoincident(thePoint, self.myOX.result())
104     self.myDOF -= 1
105     model.do()
106     if not self.myExpectFailure:
107       self.assertAlmostEqual(thePoint.y(), 0.0, delta = 1.e-6)
108       self.assertGreater(self.myEllipse.majorRadius().value(), 0.0)
109       self.assertGreater(self.myEllipse.minorRadius().value(), 0.0)
110
111   def checkPointOnLine(self, thePoint, theLineStart, theLineEnd):
112     vecP = [thePoint.x() - theLineStart.x(), thePoint.y() - theLineStart.y()]
113     vecL = [theLineEnd.x() - theLineStart.x(), theLineEnd.y() - theLineStart.y()]
114     dist = math.fabs(vecP[0] * vecL[1] - vecP[1] * vecL[0]) / math.hypot(vecL[0], vecL[1])
115
116     self.assertAlmostEqual(dist, 0.0, delta = 1.e-6)
117     self.assertGreater(self.myEllipse.majorRadius().value(), 0.0)
118     self.assertGreater(self.myEllipse.minorRadius().value(), 0.0)
119
120   def checkPointOnEllipse(self, thePoint, theEllipse):
121     firstFocus2d = GeomAPI_Pnt2d(theEllipse.firstFocus().x(), theEllipse.firstFocus().y())
122     distPF1 = model.distancePointPoint(firstFocus2d,  thePoint)
123     secondFocus2d = GeomAPI_Pnt2d(theEllipse.secondFocus().x(), theEllipse.secondFocus().y())
124     distPF2 = model.distancePointPoint(secondFocus2d,  thePoint)
125     self.assertAlmostEqual(distPF1 + distPF2, 2.0 * theEllipse.majorRadius().value(), 7)
126
127
128   def test_concident_center(self):
129     """ Test 1. Make center of ellipse coincident with the Origin
130     """
131     self.checkPointFixing(self.myCenter.coordinates())
132
133   def test_coincident_first_focus(self):
134     """ Test 2. Make first focus of ellipse coincident with the Origin
135     """
136     self.checkPointFixing(self.myFocus1.coordinates())
137
138   def test_coincident_second_focus(self):
139     """ Test 3. Make second focus of ellipse coincident with the Origin
140     """
141     self.checkPointFixing(self.myFocus2.coordinates())
142
143   def test_coincident_major_axis_start(self):
144     """ Test 4. Make start point on the major axis of ellipse coincident with the Origin
145     """
146     self.checkPointFixing(self.myMajorStart.coordinates())
147
148   def test_coincident_major_axis_end(self):
149     """ Test 5. Make end point on the major axis of ellipse coincident with the Origin
150     """
151     self.checkPointFixing(self.myMajorEnd.coordinates())
152
153   def test_coincident_minor_axis_start(self):
154     """ Test 6. Make start point on the minor axis of ellipse coincident with the Origin
155     """
156     self.checkPointFixing(self.myMinorStart.coordinates())
157     # workaround: kill the constraint to avoid instability on dump check
158     model.end()
159     model.undo()
160     model.begin()
161     self.myDOF += 2
162     self.myNbCoindicences -= 1
163
164   def test_coincident_minor_axis_end(self):
165     """ Test 7. Make end point on the minor axis of ellipse coincident with the Origin.
166                 Check solver is failed to compute the coincidence.
167     """
168     self.myExpectFailure = True
169     self.checkPointFixing(self.myMinorEnd.coordinates())
170
171
172   def test_center_on_line(self):
173     """ Test 8. Make center of ellipse coincident with the OX
174     """
175     self.checkPointOnAxis(self.myCenter.coordinates())
176
177   def test_first_focus_on_line(self):
178     """ Test 9. Make first focus of ellipse coincident with the OX
179     """
180     self.checkPointOnAxis(self.myFocus1.coordinates())
181
182   def test_second_focus_on_line(self):
183     """ Test 10. Make second focus of ellipse coincident with the OX
184     """
185     self.checkPointOnAxis(self.myFocus2.coordinates())
186
187   def test_major_axis_start_on_line(self):
188     """ Test 11. Make start point on the major axis of ellipse coincident with the OX
189     """
190     self.checkPointOnAxis(self.myMajorStart.coordinates())
191
192   def test_major_axis_end_on_line(self):
193     """ Test 12. Make end point on the major axis of ellipse coincident with the OX
194     """
195     self.checkPointOnAxis(self.myMajorEnd.coordinates())
196
197   def test_minor_axis_start_on_line(self):
198     """ Test 13. Make start point on the minor axis of ellipse coincident with the OX
199     """
200     self.checkPointOnAxis(self.myMinorStart.coordinates())
201
202   def test_minor_axis_end_on_line(self):
203     """ Test 14. Make end point on the minor axis of ellipse coincident with the OX
204     """
205     self.myExpectFailure = True
206     self.checkPointOnAxis(self.myMinorEnd.coordinates())
207
208
209   def test_origin_on_major_axis(self):
210     """ Test 15. Make origin coincident with the major axis of the ellipse
211     """
212     self.mySketch.setCoincident(self.myMajorAxis.result(), self.myOrigin.coordinates())
213     self.myDOF -= 1
214     model.do()
215     self.checkPointOnLine(self.myOrigin.coordinates(), self.myMajorStart.coordinates(), self.myMajorEnd.coordinates())
216
217   def test_origin_on_minor_axis(self):
218     """ Test 16. Make origin coincident with the minor axis of the ellipse
219     """
220     self.mySketch.setCoincident(self.myMinorAxis.result(), self.myOrigin.coordinates())
221     self.myDOF -= 1
222     model.end()
223     # solver shows wrong result
224     assert(self.mySketch.solverError() != ""), "PlaneGCS limitation: if you see this message, then PlaneGCS has solved the set of constraints correctly"
225     model.undo()
226
227     # move ellipse and set coincidence once again
228     model.begin()
229     self.mySketch.move(self.myMinorStart, 20, 10)
230     model.do()
231     self.mySketch.setCoincident(self.myMinorAxis.results()[-1], self.myOrigin.coordinates())
232     model.do()
233     self.checkPointOnLine(self.myOrigin.coordinates(), self.myMinorStart.coordinates(), self.myMinorEnd.coordinates())
234
235
236   def test_origin_on_ellipse(self):
237     """ Test 17. Make origin coincident with the ellipse
238     """
239     self.mySketch.setCoincident(self.myEllipse.results()[-1], self.myOrigin.coordinates())
240     self.myDOF -= 1
241     model.do()
242     self.checkPointOnEllipse(self.myOrigin.coordinates(), self.myEllipse)
243
244
245 if __name__ == "__main__":
246     test_program = unittest.main(exit=False)
247     assert test_program.result.wasSuccessful(), "Test failed"
248     assert model.checkPythonDump()