Salome HOME
Update copyrights
[modules/shaper.git] / src / PythonAPI / model / tests / tests.py
1 # Copyright (C) 2014-2019  CEA/DEN, EDF R&D
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 from GeomAlgoAPI import *
21 from GeomAPI import *
22 from GeomDataAPI import *
23 from ModelAPI import ModelAPI_Feature
24 import math
25 from salome.shaper.model import sketcher
26
27 TOLERANCE = 1.e-7
28
29 aShapeTypes = {
30   GeomAPI_Shape.SOLID:  "GeomAPI_Shape.SOLID",
31   GeomAPI_Shape.FACE:   "GeomAPI_Shape.FACE",
32   GeomAPI_Shape.EDGE:   "GeomAPI_Shape.EDGE",
33   GeomAPI_Shape.VERTEX: "GeomAPI_Shape.VERTEX"}
34
35
36 def generateTests(theFeature, theFeatureName, theTestsList = []):
37   """ Generates tests for theFeature.
38   :param theFeature: feature to test. Should be ModelHighAPI_Interface.
39   :param theFeatureName: feature name to put in test commands.
40   :param theTestsList: list of test to be generated. If empty generates all tests.
41   """
42   if "testNbResults" in theTestsList or len(theTestsList) == 0:
43     aNbResults = len(theFeature.results())
44     print("model.testNbResults({}, {})".format(theFeatureName, aNbResults))
45
46   if "testNbSubResults" in theTestsList or len(theTestsList) == 0:
47     aNbResults = len(theFeature.results())
48     aNbSubResults = []
49     for anIndex in range(0, aNbResults):
50       aNbSubResults.append(theFeature.results()[anIndex].numberOfSubs())
51     print("model.testNbSubResults({}, {})".format(theFeatureName, aNbSubResults))
52
53   if "testNbSubShapes" in theTestsList or len(theTestsList) == 0:
54     aNbResults = len(theFeature.results())
55     for aShapeType in aShapeTypes:
56       aNbSubShapes = []
57       for anIndex in range(0, aNbResults):
58         aShape = theFeature.results()[anIndex].resultSubShapePair()[0].shape()
59         aNbResultSubShapes = 0
60         aShapeExplorer = GeomAPI_ShapeExplorer(aShape, aShapeType)
61         while aShapeExplorer.more():
62           aNbResultSubShapes += 1
63           aShapeExplorer.next()
64         aNbSubShapes.append(aNbResultSubShapes)
65       print("model.testNbSubShapes({}, {}, {})".format(theFeatureName, aShapeTypes[aShapeType], aNbSubShapes))
66
67   if "testResultsVolumes" in theTestsList or len(theTestsList) == 0:
68     aNbResults = len(theFeature.results())
69     aResultsVolumes = []
70     for anIndex in range(0, aNbResults):
71       aResultsVolumes.append(GeomAlgoAPI_ShapeTools_volume(theFeature.results()[anIndex].resultSubShapePair()[0].shape()))
72     print("model.testResultsVolumes({}, [{}])".format(theFeatureName, ", ".join("{:0.27f}".format(i) for i in aResultsVolumes)))
73
74
75 def testNbResults(theFeature, theExpectedNbResults):
76   """ Tests number of feature results.
77   :param theFeature: feature to test.
78   :param theExpectedNbResults: expected number of results.
79   """
80   aNbResults = len(theFeature.results())
81   assert (aNbResults == theExpectedNbResults), "Number of results: {}. Expected: {}.".format(aNbResults, theExpectedNbResults)
82
83
84 def testNbSubResults(theFeature, theExpectedNbSubResults):
85   """ Tests number of feature sub-results for each result.
86   :param theFeature: feature to test.
87   :param theExpectedNbSubResults: list of sub-results numbers. Size of list should be equal to len(theFeature.results()).
88   """
89   aNbResults = len(theFeature.results())
90   aListSize = len(theExpectedNbSubResults)
91   assert (aNbResults == aListSize), "Number of results: {} not equal to list size: {}.".format(aNbResults, aListSize)
92   for anIndex in range(0, aNbResults):
93     aNbSubResults = theFeature.results()[anIndex].numberOfSubs()
94     anExpectedNbSubResults = theExpectedNbSubResults[anIndex]
95     assert (aNbSubResults == anExpectedNbSubResults), "Number of sub-results for result[{}]: {}. Expected: {}.".format(anIndex, aNbSubResults, anExpectedNbSubResults)
96
97
98 def testNbSubShapes(theFeature, theShapeType, theExpectedNbSubShapes):
99   """ Tests number of feature sub-shapes of passed type for each result.
100   :param theFeature: feature to test.
101   :param theShapeType: shape type of sub-shapes to test.
102   :param theExpectedNbSubShapes: list of sub-shapes numbers. Size of list should be equal to len(theFeature.results()).
103   """
104   aNbResults = len(theFeature.results())
105   aListSize = len(theExpectedNbSubShapes)
106   assert (aNbResults == aListSize), "Number of results: {} not equal to list size: {}.".format(aNbResults, aListSize)
107   for anIndex in range(0, aNbResults):
108     aNbResultSubShapes = 0
109     anExpectedNbSubShapes = theExpectedNbSubShapes[anIndex]
110     aShape = theFeature.results()[anIndex].resultSubShapePair()[0].shape()
111     aShapeExplorer = GeomAPI_ShapeExplorer(aShape, theShapeType)
112     while aShapeExplorer.more():
113       aNbResultSubShapes += 1
114       aShapeExplorer.next()
115     assert (aNbResultSubShapes == anExpectedNbSubShapes), "Number of sub-shapes of type {} for result[{}]: {}. Expected: {}.".format(aShapeTypes[theShapeType], anIndex, aNbResultSubShapes, anExpectedNbSubShapes)
116
117
118 def testResultsVolumes(theFeature, theExpectedResultsVolumes, theNbSignificantDigits = 7):
119   """ Tests results volumes.
120   :param theFeature: feature to test.
121   :param theExpectedResultsVolumes: list of results volumes. Size of list should be equal to len(theFeature.results()).
122   """
123   aTolerance = 10**(-theNbSignificantDigits)
124   aNbResults = len(theFeature.results())
125   aListSize = len(theExpectedResultsVolumes)
126   assert (aNbResults == aListSize), "Number of results: {} not equal to list size: {}.".format(aNbResults, aListSize)
127   for anIndex in range(0, aNbResults):
128     aResultVolume = GeomAlgoAPI_ShapeTools_volume(theFeature.results()[anIndex].resultSubShapePair()[0].shape())
129     aResultVolumeStr = "{:0.27f}".format(aResultVolume).lstrip("0").lstrip(".").lstrip("0")
130     anExpectedResultVolume = theExpectedResultsVolumes[anIndex]
131     anExpectedResultVolumeStr = "{:0.27f}".format(anExpectedResultVolume).lstrip("0").lstrip(".").lstrip("0")
132     assert math.fabs(aResultVolume - anExpectedResultVolume) < aTolerance * math.fabs(anExpectedResultVolume), "Volume of result[{}]: {:0.27f}. Expected: {:0.27f}. The first {} significant digits not equal.".format(anIndex, aResultVolume, anExpectedResultVolume, theNbSignificantDigits)
133
134 def testHaveNamingFaces(theFeature, theModel, thePartDoc) :
135   """ Tests if all faces of result have a name
136   :param theFeature: feature to test.
137   """
138   # open transaction since all the checking are performed in tests after model.end() call
139   theModel.begin()
140   # Get feature result/sub-result
141   aResult = theFeature.results()[0].resultSubShapePair()[0]
142   # Get result/sub-result shape
143   shape = aResult.shape()
144   # Create shape explorer with desired shape type
145   shapeExplorer = GeomAPI_ShapeExplorer(shape, GeomAPI_Shape.FACE)
146   # Create list, and store selections in it
147   selectionList = []
148   while shapeExplorer.more():
149     selection = theModel.selection(aResult, shapeExplorer.current()) # First argument should be result/sub-result, second is sub-shape on this result/sub-result
150     selectionList.append(selection)
151     shapeExplorer.next()
152   # Create group with this selection list
153   Group_1 = theModel.addGroup(thePartDoc, selectionList)
154   theModel.end()
155
156   # Now you can check that all selected shapes in group have right shape type and name.
157   groupFeature = Group_1.feature()
158   groupSelectionList = groupFeature.selectionList("group_list")
159   assert(groupSelectionList.size() == len(selectionList))
160   for index in range(0, groupSelectionList.size()):
161     attrSelection = groupSelectionList.value(index)
162     shape = attrSelection.value()
163     name = attrSelection.namingName()
164     assert(shape.isFace())
165     assert(name != ""), "String empty"
166
167 def testHaveNamingEdges(theFeature, theModel, thePartDoc) :
168   """ Tests if all edges of result have a name
169   :param theFeature: feature to test.
170   """
171   # Get feature result/sub-result
172   aResult = theFeature.results()[0].resultSubShapePair()[0]
173   # Get result/sub-result shape
174   shape = aResult.shape()
175   # Create shape explorer with desired shape type
176   shapeExplorer = GeomAPI_ShapeExplorer(shape, GeomAPI_Shape.EDGE)
177   # Create list, and store selections in it
178   selectionList = []
179   while shapeExplorer.more():
180     selection = theModel.selection(aResult, shapeExplorer.current()) # First argument should be result/sub-result, second is sub-shape on this result/sub-result
181     selectionList.append(selection)
182     shapeExplorer.next()
183   # Create group with this selection list
184   Group_1 = theModel.addGroup(thePartDoc, selectionList)
185   theModel.do()
186   theModel.end()
187
188   # Now you can check that all selected shapes in group have right shape type and name.
189   groupFeature = Group_1.feature()
190   groupSelectionList = groupFeature.selectionList("group_list")
191   theModel.end()
192   assert(groupSelectionList.size() == len(selectionList))
193   for index in range(0, groupSelectionList.size()):
194     attrSelection = groupSelectionList.value(index)
195     shape = attrSelection.value()
196     name = attrSelection.namingName()
197     assert(shape.isEdge())
198     assert(name != ""), "String empty"
199
200 def lowerLevelSubResults(theResult, theList):
201   """ Collects in a list all lover level sub-results (without children).
202   Auxiliary method for context correct definition.
203   """
204   nbSubs = theResult.numberOfSubs()
205   if nbSubs == 0:
206     theList.append(theResult)
207   else:
208     for sub in range(0, nbSubs):
209       lowerLevelSubResults(theResult.subResult(sub), theList)
210
211 def testHaveNamingByType(theFeature, theModel, thePartDoc, theSubshapeType) :
212   """ Tests if all sub-shapes of result have a unique name
213   :param theFeature: feature to test.
214   :param theSubshapeType: type of sub-shape
215   """
216   if not theFeature.results():
217     return
218   aFirstRes = theFeature.results()[0]
219   aResList = []
220   lowerLevelSubResults(aFirstRes, aResList)
221
222   selectionList = []
223   shapesList = [] # to append only unique shapes (not isSame)
224   for aR in aResList:
225     # Get feature result/sub-result
226     aResult = aR.resultSubShapePair()[0]
227     # Get result/sub-result shape
228     shape = aResult.shape()
229     # Create shape explorer with desired shape type
230     shapeExplorer = GeomAPI_ShapeExplorer(shape, theSubshapeType)
231     # Create list, and store selections in it
232     while shapeExplorer.more():
233       current = shapeExplorer.current()
234       if current.isEdge() and GeomAPI.GeomAPI_Edge(current).isDegenerated(): # skip degenerative edges because they are not selected
235         shapeExplorer.next()
236         continue
237       aDuplicate = False
238       for alreadyThere in shapesList:
239         if alreadyThere.isSame(current):
240           aDuplicate = True
241       if aDuplicate:
242         shapeExplorer.next()
243         continue
244       shapesList.append(current)
245       selection = theModel.selection(aResult, current) # First argument should be result/sub-result, second is sub-shape on this result/sub-result
246       selectionList.append(selection)
247       shapeExplorer.next()
248   # Create group with this selection list
249   # (do not create group if nothing is selected)
250   if (len(selectionList) == 0):
251     return
252   Group_1 = theModel.addGroup(thePartDoc, selectionList)
253   theModel.do()
254
255   groupSelectionList = Group_1.feature().selectionList("group_list")
256   assert(groupSelectionList.size() == len(selectionList))
257
258   # Check that all selected shapes in group have right shape type and unique name.
259   checkGroup(Group_1, theSubshapeType)
260
261 def testHaveNamingSubshapes(theFeature, theModel, thePartDoc) :
262   """ Tests if all vertices/edges/faces of result have a unique name
263   :param theFeature: feature to test.
264   """
265   assert(len(theFeature.results()) > 0)
266   testHaveNamingByType(theFeature, theModel, thePartDoc, GeomAPI_Shape.VERTEX)
267   testHaveNamingByType(theFeature, theModel, thePartDoc, GeomAPI_Shape.EDGE)
268   testHaveNamingByType(theFeature, theModel, thePartDoc, GeomAPI_Shape.FACE)
269
270 def testNbSubFeatures(theComposite, theKindOfSub, theExpectedCount):
271   """ Tests number of sub-features of the given type
272   :param theComposite     composite feature to check its subs
273   :param theKindOfSub     kind of sub-feature to calculate count
274   :param theExpectedCount expected number of sub-features
275   """
276   count = 0
277   for aSub in theComposite.features().list():
278     aFeature = ModelAPI_Feature.feature(aSub)
279     if aFeature is not None and aFeature.getKind() == theKindOfSub:
280        count += 1
281   assert (count == theExpectedCount), "Number of sub-features of type {}: {}, expected {}".format(theKindOfSub, count, theExpectedCount)
282
283 def assertSketchArc(theArcFeature):
284   """ Tests whether the arc is correctly defined
285   """
286   aCenterPnt = geomDataAPI_Point2D(theArcFeature.attribute("center_point"))
287   aStartPnt = geomDataAPI_Point2D(theArcFeature.attribute("start_point"))
288   aEndPnt = geomDataAPI_Point2D(theArcFeature.attribute("end_point"))
289   aRadius = theArcFeature.real("radius")
290   aDistCS = sketcher.tools.distancePointPoint(aCenterPnt, aStartPnt)
291   aDistCE = sketcher.tools.distancePointPoint(aCenterPnt, aEndPnt)
292   assert math.fabs(aDistCS - aDistCE) < TOLERANCE, "Wrong arc: center-start distance {}, center-end distance {}".format(aDistCS, aDistCE)
293   assert math.fabs(aRadius.value() -aDistCS) < TOLERANCE, "Wrong arc: radius is {0}, expected {1}".format(aRadius.value(), aDistCS)
294
295 def checkResult(theFeature,theModel,NbRes,NbSubRes,NbSolid,NbFace,NbEdge,NbVertex):
296   """ Tests numbers of sub-shapes in results
297   """
298   theModel.testNbResults(theFeature, NbRes)
299   theModel.testNbSubResults(theFeature, NbSubRes)
300   theModel.testNbSubShapes(theFeature, GeomAPI_Shape.SOLID, NbSolid)
301   theModel.testNbSubShapes(theFeature, GeomAPI_Shape.FACE, NbFace)
302   theModel.testNbSubShapes(theFeature, GeomAPI_Shape.EDGE, NbEdge)
303   theModel.testNbSubShapes(theFeature, GeomAPI_Shape.VERTEX, NbVertex)
304
305 def checkGroup(theGroup, theShapeType):
306   """ Check that all selected shapes in group have correct shape type and unique name
307   """
308   groupFeature = theGroup.feature()
309   groupSelectionList = groupFeature.selectionList("group_list")
310   presented_names = set()
311   for index in range(0, groupSelectionList.size()):
312     attrSelection = groupSelectionList.value(index)
313     shape = attrSelection.value()
314     name = attrSelection.namingName()
315     if theShapeType == GeomAPI_Shape.VERTEX:
316       assert(shape.isVertex())
317     elif theShapeType == GeomAPI_Shape.EDGE:
318       assert(shape.isEdge())
319     elif theShapeType == GeomAPI_Shape.FACE:
320       assert(shape.isFace())
321     assert(name != ""), "String empty"
322     presented_names.add(name)
323   assert(len(presented_names) == groupSelectionList.size()), "Some names are not unique"