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
20 from GeomAlgoAPI import *
22 from GeomDataAPI import *
23 from ModelAPI import ModelAPI_Feature, ModelAPI_Session
24 from ModelHighAPI import *
26 from salome.shaper.model import sketcher
31 GeomAPI_Shape.SOLID: "GeomAPI_Shape.SOLID",
32 GeomAPI_Shape.FACE: "GeomAPI_Shape.FACE",
33 GeomAPI_Shape.EDGE: "GeomAPI_Shape.EDGE",
34 GeomAPI_Shape.VERTEX: "GeomAPI_Shape.VERTEX"}
37 def generateTests(theFeature, theFeatureName, theTestsList = []):
38 """ Generates tests for theFeature.
39 :param theFeature: feature to test. Should be ModelHighAPI_Interface.
40 :param theFeatureName: feature name to put in test commands.
41 :param theTestsList: list of test to be generated. If empty generates all tests.
43 if "testNbResults" in theTestsList or len(theTestsList) == 0:
44 aNbResults = len(theFeature.results())
45 print("model.testNbResults({}, {})".format(theFeatureName, aNbResults))
47 if "testNbSubResults" in theTestsList or len(theTestsList) == 0:
48 aNbResults = len(theFeature.results())
50 for anIndex in range(0, aNbResults):
51 aNbSubResults.append(theFeature.results()[anIndex].numberOfSubs())
52 print("model.testNbSubResults({}, {})".format(theFeatureName, aNbSubResults))
54 if "testNbSubShapes" in theTestsList or len(theTestsList) == 0:
55 aNbResults = len(theFeature.results())
56 for aShapeType in aShapeTypes:
58 for anIndex in range(0, aNbResults):
59 aShape = theFeature.results()[anIndex].resultSubShapePair()[0].shape()
60 aNbResultSubShapes = 0
61 aShapeExplorer = GeomAPI_ShapeExplorer(aShape, aShapeType)
62 while aShapeExplorer.more():
63 aNbResultSubShapes += 1
65 aNbSubShapes.append(aNbResultSubShapes)
66 print("model.testNbSubShapes({}, {}, {})".format(theFeatureName, aShapeTypes[aShapeType], aNbSubShapes))
68 if "testResultsVolumes" in theTestsList or len(theTestsList) == 0:
69 aNbResults = len(theFeature.results())
71 for anIndex in range(0, aNbResults):
72 aResultsVolumes.append(GeomAlgoAPI_ShapeTools_volume(theFeature.results()[anIndex].resultSubShapePair()[0].shape()))
73 print("model.testResultsVolumes({}, [{}])".format(theFeatureName, ", ".join("{:0.27f}".format(i) for i in aResultsVolumes)))
75 if "testResultsAreas" in theTestsList or len(theTestsList) == 0:
76 aNbResults = len(theFeature.results())
78 for anIndex in range(0, aNbResults):
79 aResultsAreas.append(GeomAlgoAPI_ShapeTools_area(theFeature.results()[anIndex].resultSubShapePair()[0].shape()))
80 print("model.testResultsAreas({}, [{}])".format(theFeatureName, ", ".join("{:0.27f}".format(i) for i in aResultsAreas)))
83 def testNbResults(theFeature, theExpectedNbResults):
84 """ Tests number of feature results.
85 :param theFeature: feature to test.
86 :param theExpectedNbResults: expected number of results.
88 aNbResults = len(theFeature.results())
89 assert (aNbResults == theExpectedNbResults), "Number of results: {}. Expected: {}.".format(aNbResults, theExpectedNbResults)
92 def testNbSubResults(theFeature, theExpectedNbSubResults):
93 """ Tests number of feature sub-results for each result.
94 :param theFeature: feature to test.
95 :param theExpectedNbSubResults: list of sub-results numbers. Size of list should be equal to len(theFeature.results()).
97 aNbResults = len(theFeature.results())
98 aListSize = len(theExpectedNbSubResults)
99 assert (aNbResults == aListSize), "Number of results: {} not equal to list size: {}.".format(aNbResults, aListSize)
100 for anIndex in range(0, aNbResults):
101 aNbSubResults = theFeature.results()[anIndex].numberOfSubs()
102 anExpectedNbSubResults = theExpectedNbSubResults[anIndex]
103 assert (aNbSubResults == anExpectedNbSubResults), "Number of sub-results for result[{}]: {}. Expected: {}.".format(anIndex, aNbSubResults, anExpectedNbSubResults)
106 def testNbSubShapes(theFeature, theShapeType, theExpectedNbSubShapes):
107 """ Tests number of feature sub-shapes of passed type for each result.
108 :param theFeature: feature to test.
109 :param theShapeType: shape type of sub-shapes to test.
110 :param theExpectedNbSubShapes: list of sub-shapes numbers. Size of list should be equal to len(theFeature.results()).
112 aNbResults = len(theFeature.results())
113 aListSize = len(theExpectedNbSubShapes)
114 assert (aNbResults == aListSize), "Number of results: {} not equal to list size: {}.".format(aNbResults, aListSize)
115 for anIndex in range(0, aNbResults):
116 aNbResultSubShapes = 0
117 anExpectedNbSubShapes = theExpectedNbSubShapes[anIndex]
118 aShape = theFeature.results()[anIndex].resultSubShapePair()[0].shape()
119 aShapeExplorer = GeomAPI_ShapeExplorer(aShape, theShapeType)
120 while aShapeExplorer.more():
121 aNbResultSubShapes += 1
122 aShapeExplorer.next()
123 assert (aNbResultSubShapes == anExpectedNbSubShapes), "Number of sub-shapes of type {} for result[{}]: {}. Expected: {}.".format(aShapeTypes[theShapeType], anIndex, aNbResultSubShapes, anExpectedNbSubShapes)
126 def testNbUniqueSubShapes(theFeature, theShapeType, theExpectedNbSubShapes):
127 """ Tests number of unique feature sub-shapes of passed type for each result.
128 :param theFeature: feature to test.
129 :param theShapeType: shape type of sub-shapes to test.
130 :param theExpectedNbSubShapes: list of sub-shapes numbers. Size of list should be equal to len(theFeature.results()).
132 aResults = theFeature.feature().results()
133 aNbResults = len(aResults)
134 aListSize = len(theExpectedNbSubShapes)
135 assert (aNbResults == aListSize), "Number of results: {} not equal to list size: {}.".format(aNbResults, aListSize)
136 for anIndex in range(0, aNbResults):
137 aNbResultSubShapes = 0
138 anExpectedNbSubShapes = theExpectedNbSubShapes[anIndex]
139 aNbResultSubShapes = aResults[anIndex].shape().subShapes(theShapeType, True).size()
140 assert (aNbResultSubShapes == anExpectedNbSubShapes), "Number of sub-shapes of type {} for result[{}]: {}. Expected: {}.".format(aShapeTypes[theShapeType], anIndex, aNbResultSubShapes, anExpectedNbSubShapes)
143 def testCompound(theFeature, NbSubRes, NbSolid, NbFace, NbEdge, NbVertex):
144 """ Tests number of unique sub-shapes in compound result
146 aResults = theFeature.feature().results()
147 aNbResults = len(aResults)
148 assert (aNbResults == 1), "Number of results: {} not equal to 1.".format(aNbResults)
149 assert aResults[0].shape().isCompound(), "Result shape type: {}. Expected: COMPOUND.".format(aResults[0].shape().shapeTypeStr())
150 testNbSubResults(theFeature, NbSubRes)
151 testNbUniqueSubShapes(theFeature, GeomAPI_Shape.SOLID, NbSolid)
152 testNbUniqueSubShapes(theFeature, GeomAPI_Shape.FACE, NbFace)
153 testNbUniqueSubShapes(theFeature, GeomAPI_Shape.EDGE, NbEdge)
154 testNbUniqueSubShapes(theFeature, GeomAPI_Shape.VERTEX, NbVertex)
157 def testCompSolid(theFeature, NbSubRes, NbSolid, NbFace, NbEdge, NbVertex):
158 """ Tests number of unique sub-shapes in compsolid result
160 aResults = theFeature.feature().results()
161 aNbResults = len(aResults)
162 assert (aNbResults == 1), "Number of results: {} not equal to 1.".format(aNbResults)
163 assert aResults[0].shape().isCompSolid(), "Result shape type: {}. Expected: COMPSOLID.".format(aResults[0].shape().shapeTypeStr())
164 testNbSubResults(theFeature, NbSubRes)
165 testNbUniqueSubShapes(theFeature, GeomAPI_Shape.SOLID, NbSolid)
166 testNbUniqueSubShapes(theFeature, GeomAPI_Shape.FACE, NbFace)
167 testNbUniqueSubShapes(theFeature, GeomAPI_Shape.EDGE, NbEdge)
168 testNbUniqueSubShapes(theFeature, GeomAPI_Shape.VERTEX, NbVertex)
171 def testResults(theFeature, NbRes, NbSubRes, NbShell, NbFace, NbEdge, NbVertex):
172 """ Tests numbers of unique sub-shapes in the results
174 aResults = theFeature.feature().results()
175 aNbResults = len(aResults)
176 assert (aNbResults == NbRes), "Number of results: {} not equal to {}}.".format(aNbResults, NbRes)
177 testNbSubResults(theFeature, NbSubRes)
178 testNbUniqueSubShapes(theFeature, GeomAPI_Shape.SHELL, NbShell)
179 testNbUniqueSubShapes(theFeature, GeomAPI_Shape.FACE, NbFace)
180 testNbUniqueSubShapes(theFeature, GeomAPI_Shape.EDGE, NbEdge)
181 testNbUniqueSubShapes(theFeature, GeomAPI_Shape.VERTEX, NbVertex)
184 def testResultsVolumes(theFeature, theExpectedResultsVolumes, theNbSignificantDigits = 7):
185 """ Tests results volumes.
186 :param theFeature: feature to test.
187 :param theExpectedResultsVolumes: list of results volumes. Size of list should be equal to len(theFeature.results()).
189 aTolerance = 10**(-theNbSignificantDigits)
190 aNbResults = len(theFeature.results())
191 aListSize = len(theExpectedResultsVolumes)
192 assert (aNbResults == aListSize), "Number of results: {} not equal to list size: {}.".format(aNbResults, aListSize)
193 for anIndex in range(0, aNbResults):
194 aResultVolume = GeomAlgoAPI_ShapeTools_volume(theFeature.results()[anIndex].resultSubShapePair()[0].shape())
195 aResultVolumeStr = "{:0.27f}".format(aResultVolume).lstrip("0").lstrip(".").lstrip("0")
196 anExpectedResultVolume = theExpectedResultsVolumes[anIndex]
197 anExpectedResultVolumeStr = "{:0.27f}".format(anExpectedResultVolume).lstrip("0").lstrip(".").lstrip("0")
198 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)
201 def testResultsAreas(theFeature, theExpectedResultsVolumes, theNbSignificantDigits = 7):
202 """ Tests results areas.
203 :param theFeature: feature to test.
204 :param theExpectedResultsAreas: list of results areas. Size of list should be equal to len(theFeature.results()).
206 aTolerance = 10**(-theNbSignificantDigits)
207 aNbResults = len(theFeature.results())
208 aListSize = len(theExpectedResultsVolumes)
209 assert (aNbResults == aListSize), "Number of results: {} not equal to list size: {}.".format(aNbResults, aListSize)
210 for anIndex in range(0, aNbResults):
211 aResultVolume = GeomAlgoAPI_ShapeTools_area(theFeature.results()[anIndex].resultSubShapePair()[0].shape())
212 aResultVolumeStr = "{:0.27f}".format(aResultVolume).lstrip("0").lstrip(".").lstrip("0")
213 anExpectedResultVolume = theExpectedResultsVolumes[anIndex]
214 anExpectedResultVolumeStr = "{:0.27f}".format(anExpectedResultVolume).lstrip("0").lstrip(".").lstrip("0")
215 assert math.fabs(aResultVolume - anExpectedResultVolume) <= aTolerance * math.fabs(anExpectedResultVolume), "Area of result[{}]: {:0.27f}. Expected: {:0.27f}. The first {} significant digits not equal.".format(anIndex, aResultVolume, anExpectedResultVolume, theNbSignificantDigits)
218 def testHaveNamingFaces(theFeature, theModel, thePartDoc) :
219 """ Tests if all faces of result have a name
220 :param theFeature: feature to test.
222 # open transaction since all the checking are performed in tests after model.end() call
224 # Get feature result/sub-result
225 aResult = theFeature.results()[0].resultSubShapePair()[0]
226 # Get result/sub-result shape
227 shape = aResult.shape()
228 # Create shape explorer with desired shape type
229 shapeExplorer = GeomAPI_ShapeExplorer(shape, GeomAPI_Shape.FACE)
230 # Create list, and store selections in it
232 while shapeExplorer.more():
233 selection = theModel.selection(aResult, shapeExplorer.current()) # First argument should be result/sub-result, second is sub-shape on this result/sub-result
234 selectionList.append(selection)
236 # Create group with this selection list
237 Group_1 = theModel.addGroup(thePartDoc, selectionList)
240 # Now you can check that all selected shapes in group have right shape type and name.
241 groupFeature = Group_1.feature()
242 groupSelectionList = groupFeature.selectionList("group_list")
243 assert(groupSelectionList.size() == len(selectionList))
244 for index in range(0, groupSelectionList.size()):
245 attrSelection = groupSelectionList.value(index)
246 shape = attrSelection.value()
247 name = attrSelection.namingName()
248 assert(shape.isFace())
249 assert(name != ""), "String empty"
251 def testHaveNamingEdges(theFeature, theModel, thePartDoc) :
252 """ Tests if all edges of result have a name
253 :param theFeature: feature to test.
255 # Get feature result/sub-result
256 aResult = theFeature.results()[0].resultSubShapePair()[0]
257 # Get result/sub-result shape
258 shape = aResult.shape()
259 # Create shape explorer with desired shape type
260 shapeExplorer = GeomAPI_ShapeExplorer(shape, GeomAPI_Shape.EDGE)
261 # Create list, and store selections in it
263 while shapeExplorer.more():
264 selection = theModel.selection(aResult, shapeExplorer.current()) # First argument should be result/sub-result, second is sub-shape on this result/sub-result
265 selectionList.append(selection)
267 # Create group with this selection list
268 Group_1 = theModel.addGroup(thePartDoc, selectionList)
272 # Now you can check that all selected shapes in group have right shape type and name.
273 groupFeature = Group_1.feature()
274 groupSelectionList = groupFeature.selectionList("group_list")
276 assert(groupSelectionList.size() == len(selectionList))
277 for index in range(0, groupSelectionList.size()):
278 attrSelection = groupSelectionList.value(index)
279 shape = attrSelection.value()
280 name = attrSelection.namingName()
281 assert(shape.isEdge())
282 assert(name != ""), "String empty"
284 def lowerLevelSubResults(theResult, theList):
285 """ Collects in a list all lover level sub-results (without children).
286 Auxiliary method for context correct definition.
288 nbSubs = theResult.numberOfSubs()
290 theList.append(theResult)
292 for sub in range(0, nbSubs):
293 lowerLevelSubResults(theResult.subResult(sub), theList)
295 def testHaveNamingByType(theFeature, theModel, thePartDoc, theSubshapeType) :
296 """ Tests if all sub-shapes of result have a unique name
297 :param theFeature: feature to test.
298 :param theSubshapeType: type of sub-shape
300 if not theFeature.results():
302 aFirstRes = theFeature.results()[0]
304 lowerLevelSubResults(aFirstRes, aResList)
307 shapesList = [] # to append only unique shapes (not isSame)
309 # Get feature result/sub-result
310 aResult = aR.resultSubShapePair()[0]
311 # Get result/sub-result shape
312 shape = aResult.shape()
313 # Create shape explorer with desired shape type
314 shapeExplorer = GeomAPI_ShapeExplorer(shape, theSubshapeType)
315 # Create list, and store selections in it
316 while shapeExplorer.more():
317 current = shapeExplorer.current()
318 if current.isEdge() and GeomAPI.GeomAPI_Edge(current).isDegenerated(): # skip degenerative edges because they are not selected
322 for alreadyThere in shapesList:
323 if alreadyThere.isSame(current):
328 shapesList.append(current)
329 selection = theModel.selection(aResult, current) # First argument should be result/sub-result, second is sub-shape on this result/sub-result
330 selectionList.append(selection)
332 # Create group with this selection list
333 # (do not create group if nothing is selected)
334 if (len(selectionList) == 0):
336 Group_1 = theModel.addGroup(thePartDoc, selectionList)
339 groupSelectionList = Group_1.feature().selectionList("group_list")
340 assert(groupSelectionList.size() == len(selectionList))
342 # Check that all selected shapes in group have right shape type and unique name.
343 checkGroup(Group_1, theSubshapeType)
345 def testHaveNamingSubshapes(theFeature, theModel, thePartDoc) :
346 """ Tests if all vertices/edges/faces of result have a unique name
347 :param theFeature: feature to test.
349 assert(len(theFeature.results()) > 0)
350 testHaveNamingByType(theFeature, theModel, thePartDoc, GeomAPI_Shape.VERTEX)
351 testHaveNamingByType(theFeature, theModel, thePartDoc, GeomAPI_Shape.EDGE)
352 testHaveNamingByType(theFeature, theModel, thePartDoc, GeomAPI_Shape.FACE)
354 def testNbSubFeatures(theComposite, theKindOfSub, theExpectedCount):
355 """ Tests number of sub-features of the given type
356 :param theComposite composite feature to check its subs
357 :param theKindOfSub kind of sub-feature to calculate count
358 :param theExpectedCount expected number of sub-features
361 for aSub in theComposite.features().list():
362 aFeature = ModelAPI_Feature.feature(aSub)
363 if aFeature is not None and aFeature.getKind() == theKindOfSub:
365 assert (count == theExpectedCount), "Number of sub-features of type {}: {}, expected {}".format(theKindOfSub, count, theExpectedCount)
367 def assertSketchArc(theArcFeature):
368 """ Tests whether the arc is correctly defined
370 aCenterPnt = geomDataAPI_Point2D(theArcFeature.attribute("center_point"))
371 aStartPnt = geomDataAPI_Point2D(theArcFeature.attribute("start_point"))
372 aEndPnt = geomDataAPI_Point2D(theArcFeature.attribute("end_point"))
373 aRadius = theArcFeature.real("radius")
374 aDistCS = sketcher.tools.distancePointPoint(aCenterPnt, aStartPnt)
375 aDistCE = sketcher.tools.distancePointPoint(aCenterPnt, aEndPnt)
376 assert math.fabs(aDistCS - aDistCE) < TOLERANCE, "Wrong arc: center-start distance {}, center-end distance {}".format(aDistCS, aDistCE)
377 assert math.fabs(aRadius.value() -aDistCS) < TOLERANCE, "Wrong arc: radius is {0}, expected {1}".format(aRadius.value(), aDistCS)
379 def checkResult(theFeature,theModel,NbRes,NbSubRes,NbSolid,NbFace,NbEdge,NbVertex):
380 """ Tests numbers of sub-shapes in results
382 theModel.testNbResults(theFeature, NbRes)
383 theModel.testNbSubResults(theFeature, NbSubRes)
384 theModel.testNbSubShapes(theFeature, GeomAPI_Shape.SOLID, NbSolid)
385 theModel.testNbSubShapes(theFeature, GeomAPI_Shape.FACE, NbFace)
386 theModel.testNbSubShapes(theFeature, GeomAPI_Shape.EDGE, NbEdge)
387 theModel.testNbSubShapes(theFeature, GeomAPI_Shape.VERTEX, NbVertex)
389 def checkGroup(theGroup, theShapeType):
390 """ Check that all selected shapes in group have correct shape type and unique name
392 groupFeature = theGroup.feature()
393 groupSelectionList = groupFeature.selectionList("group_list")
394 presented_names = set()
395 for index in range(0, groupSelectionList.size()):
396 attrSelection = groupSelectionList.value(index)
397 shape = attrSelection.value()
398 name = attrSelection.namingName()
399 if theShapeType == GeomAPI_Shape.VERTEX:
400 assert(shape.isVertex())
401 elif theShapeType == GeomAPI_Shape.EDGE:
402 assert(shape.isEdge())
403 elif theShapeType == GeomAPI_Shape.FACE:
404 assert(shape.isFace())
405 assert(name != ""), "String empty"
406 presented_names.add(name)
407 assert(len(presented_names) == groupSelectionList.size()), "Some names are not unique"
409 def createSubShape(thePartDoc, theModel, theSelection):
410 """ Create feature according to the type of the given subshape
412 if theSelection.shapeType() == "VERTEX":
413 return theModel.addVertex(thePartDoc, [theSelection])
414 elif theSelection.shapeType() == "EDGE":
415 return theModel.addEdge(thePartDoc, [theSelection])
416 elif theSelection.shapeType() == "FACE":
417 return theModel.addFace(thePartDoc, [theSelection])
419 def checkFilter(thePartDoc, theModel, theFilter, theShapesList):
420 """ Check filter's work on specified shape.
421 Shapes given as a dictionary of selection and expected result.
423 aFiltersFactory = ModelAPI_Session.get().filters()
424 for sel, res in theShapesList.items():
427 shapeType = "UNKNOWN"
428 if sel.variantType() == ModelHighAPI_Selection.VT_ResultSubShapePair:
429 parent = sel.resultSubShapePair()[0]
430 shape = sel.resultSubShapePair()[1]
432 shape = sel.resultSubShapePair()[0].shape()
433 shapeName = sel.name()
434 shapeType = shape.shapeTypeStr()
438 subShapeFeature = createSubShape(thePartDoc, theModel, sel)
440 parent = subShapeFeature.results()[0].resultSubShapePair()[0]
441 shape = subShapeFeature.results()[0].resultSubShapePair()[0].shape()
442 shapeType = sel.typeSubShapeNamePair()[0]
443 shapeName = sel.typeSubShapeNamePair()[1]
444 assert aFiltersFactory.isValid(theFilter.feature(), parent, shape) == res, "Filter result for {} \"{}\" incorrect. Expected {}.".format(shapeType, shapeName, res)