Salome HOME
[bos #41409][FORUM] (2024) kindOfShape() bug for CONE2D
[modules/geom.git] / doc / salome / examples / kind_of_shape_cone.py
1 # Sample: KindOfShape method for faces, which are results of partitioning of a conical surface with a prism with complex base.
2 # Faces of the prism are not perpendicular to cone axis, therefore contour-wires of resulting cone fragments are composed of lines and 2-order curves.
3
4 import sys
5 import salome
6
7 salome.salome_init()
8 import salome_notebook
9 notebook = salome_notebook.NoteBook()
10
11 ###
12 ### GEOM component
13 ###
14
15 import GEOM
16 from salome.geom import geomBuilder
17 import math
18 import SALOMEDS
19
20
21 def approximatelyEqual(a, b, epsilon = 1e-5):
22    return abs(a - b) <= ((abs(b) if (abs(a) < abs(b)) else abs(a)) * epsilon)
23
24
25 def assertShapeKindEquals(iShapeInfo, iKind):
26   assert (len(iShapeInfo) > 0), "Yielded data array is empty."
27   assert (iShapeInfo[0] == iKind), f"Expected shape kind is {iKind}, but yielded kind is {iShapeInfo[0]}."
28
29
30 def assertConePropsEqual(iShapeName, iShapeInfo, iExpectedShapeInfo):
31    assertShapeKindEquals(iShapeInfo, geompy.kind.CONE2D)
32    assert (len(iShapeInfo) == len(iExpectedShapeInfo)), f"{iShapeName}: Yielded data array is of unexpected length."
33    for idx in range(1, len(iShapeInfo)):
34       assert (approximatelyEqual(iShapeInfo[idx], iExpectedShapeInfo[idx])), f"{iShapeName}: Yielded data array element is not equal to the expected value."
35
36
37 def assertConeInfoEquals(iFace, iExpectedShapeInfo, iAddRestoredConeToStudy = False):
38   ShapeInfo = geompy.KindOfShape(iFace)
39   print("ShapeInfo of " + iFace.GetName() + " = ", end = "")
40   print(ShapeInfo, ', ')
41   assertConePropsEqual(iFace.GetName(), ShapeInfo, iExpectedShapeInfo)
42
43   if (iAddRestoredConeToStudy):
44     BottomLidCenter = geompy.MakeVertex(ShapeInfo[1], ShapeInfo[2], ShapeInfo[3])
45     AxisAuxPnt = geompy.MakeVertex(ShapeInfo[1] + ShapeInfo[4], ShapeInfo[2] + ShapeInfo[5], ShapeInfo[3] + ShapeInfo[6])
46     Axis = geompy.MakeVector(BottomLidCenter, AxisAuxPnt)
47     R1 = ShapeInfo[7] # Bottom lid radius.
48     R2 = ShapeInfo[8] # Top lid radius.
49     H = ShapeInfo[9]
50     RestoredCone = geompy.MakeCone(BottomLidCenter, Axis, R1, R2, H)
51     geompy.addToStudy(RestoredCone, iFace.GetName() + '__RestoredCone')
52
53
54 # iExpectedConeFragmentShapeInfos is a dictionary of [IndexOfFace, ExpectedShapeInfoOfFace]. IndexOfFace is zero-based index, not one-based one as in Shaper GUI!
55 def partitionConeAndAssertShapeInfosEqual(iCone, iPartitioningShape, iExpectedConeFragmentShapeInfos, iAddResultsToStudy):
56   PartitionedCone = geompy.MakePartition([iCone], [iPartitioningShape], [], [], geompy.ShapeType["FACE"], 0, [], 0)
57   if (iAddResultsToStudy):
58     geompy.addToStudy(PartitionedCone, "Partitioned" + iCone.GetName())
59
60   ConeFragments = geompy.ExtractShapes(PartitionedCone, geompy.ShapeType["FACE"], True)
61   ConeFragmentsIdxs = iExpectedConeFragmentShapeInfos.keys()
62   for ConeFragmentIdx in ConeFragmentsIdxs:
63     assert (ConeFragmentIdx < len(ConeFragments)), f"Num of faces, {iCone.GetName()} is partitioned into, <= {ConeFragmentIdx} (zero-based index)."
64     ConeFragment = ConeFragments[ConeFragmentIdx]
65     ConeFragmentName = f"Partitioned{iCone.GetName()}_Face_{ConeFragmentIdx+1}" # Add index to a name as Shaper GUI does.
66
67     if (iAddResultsToStudy):
68       geompy.addToStudyInFather(PartitionedCone, ConeFragment, ConeFragmentName)
69     else:
70       ConeFragment.SetName(ConeFragmentName)
71
72     assertConeInfoEquals(ConeFragment, iExpectedConeFragmentShapeInfos[ConeFragmentIdx], iAddResultsToStudy)
73
74
75 geompy = geomBuilder.New()
76
77 OriginalConeBaseCenter = geompy.MakeVertex(100, 130, -60)
78 OriginalConeAxisAuxPnt = geompy.MakeVertex(100, 230, 40)
79 OriginalConeAxis = geompy.MakeVector(OriginalConeBaseCenter, OriginalConeAxisAuxPnt)
80 OriginalCone = geompy.MakeCone(OriginalConeBaseCenter, OriginalConeAxis, 100, 50, 300)
81 PrismSubstrateCenter = geompy.MakeVertex(100, 1000, 50)
82 PrismDirAuxPnt = geompy.MakeVertex(100, 950, 50)
83 PrismDir = geompy.MakeVector(PrismSubstrateCenter, PrismDirAuxPnt)
84 PrismSubstrate = geompy.MakeDiskPntVecR(PrismSubstrateCenter, PrismDir, 100)
85 sk = geompy.Sketcher2D()
86 sk.addPoint(0.395986, 43.346713)
87 sk.addSegmentAbsolute(66.321537, 41.733575)
88 sk.addSegmentAbsolute(80.619408, -2.852314)
89 sk.addSegmentAbsolute(67.641539, -38.565150)
90 sk.addSegmentAbsolute(22.193602, -56.632163)
91 sk.addSegmentAbsolute(-19.060136, -51.084351)
92 sk.addSegmentAbsolute(-60.823572, 34.825751)
93 sk.addSegmentAbsolute(-13.047004, 55.727527)
94 sk.close()
95 PrismBase = sk.wire(PrismSubstrate)
96 Prism = geompy.MakePrismVecH(PrismBase, PrismDir, 1400)
97 geompy.addToStudy( OriginalConeBaseCenter, 'OriginalConeBaseCenter' )
98 geompy.addToStudy( OriginalConeAxisAuxPnt, 'OriginalConeAxisAuxPnt' )
99 geompy.addToStudy( OriginalConeAxis, 'OriginalConeAxis' )
100 geompy.addToStudy( OriginalCone, 'OriginalCone' )
101 geompy.addToStudy( PrismSubstrateCenter, 'PrismSubstrateCenter' )
102 geompy.addToStudy( PrismDirAuxPnt, 'PrismDirAuxPnt' )
103 geompy.addToStudy( PrismDir, 'PrismDir' )
104 geompy.addToStudy( PrismSubstrate, 'PrismSubstrate' )
105 geompy.addToStudy( PrismBase, 'PrismBase' )
106 geompy.addToStudy( Prism, 'Prism' )
107
108 # Test on the original cone
109 ExpectedOriginalConeFragmentsShapeInfos = {
110   3: ["CONE2D", 100.0, 215.76160602318674, 25.761606023186744, 0.0, 0.7071067811865475, 0.7071067811865475, 79.7857956051852, 54.62305376134459, 150.9764510630437],
111   5: ["CONE2D", 100.0, 129.99999999999753, -60.000000000002466, 0.0, 0.7071067811865475, 0.7071067811865475, 100.00000000000058, 69.82277418813575, 181.06335487118898],
112   11: ["CONE2D", 100.0, 216.57653245407857, 26.57653245407856, 0.0, 0.7071067811865475, 0.7071067811865475, 79.59371560336794, 52.95933239773038, 159.80629923382543]
113 }
114 partitionConeAndAssertShapeInfosEqual(OriginalCone, Prism, ExpectedOriginalConeFragmentsShapeInfos, True)
115
116 # Test on isotropically scaled cone. Non-isotropical scaling does not preserve shape kind - it is desired behavior.
117 ScaledCone = geompy.MakeScaleTransform(OriginalCone, OriginalConeAxisAuxPnt, 2)
118 ScaledCone.SetName('ScaledCone')
119 ExpectedScaledConeFragmentsShapeInfos = {
120   4: ["CONE2D", 100.0, 29.9999999999999, -160.00000000000009, 0.0, 0.7071067811865475, 0.7071067811865475, 200.00000000000003, 162.64508449690112, 224.1294930185934],
121   6: ["CONE2D", 100.0, 262.09898500769475, 72.09898500769472, 0.0, 0.7071067811865475, 0.7071067811865475, 145.2937445981814, 120.13428858458612, 150.95673608157182],
122   12: ["CONE2D", 100.0, 262.8999708414969, 72.8999708414969, 0.0, 0.7071067811865475, 0.7071067811865475, 145.10495042660943, 117.46838914559419, 165.8193676860916]
123 }
124 partitionConeAndAssertShapeInfosEqual(ScaledCone, Prism, ExpectedScaledConeFragmentsShapeInfos, False)
125
126 # Test on a cone, mirrored relative to a point.
127 PntMirroredCone = geompy.MakeMirrorByPoint(OriginalCone, OriginalConeAxisAuxPnt)
128 PntMirroredCone.SetName('PntMirroredCone')
129 ExpectedPntMirroredConeFragmentsShapeInfos = {
130   2: ["CONE2D", 100.0, 229.8712015945071, 39.87120159450711, -0.0, -0.7071067811865475, -0.7071067811865475, 76.39941588513841, 51.25530645152799, 150.8646566016625],
131   7: ["CONE2D", 100.0, 330.0, 140.0, -0.0, -0.7071067811865475, -0.7071067811865475, 100.0, 71.73019727352477, 169.61881635885143],
132   10: ["CONE2D", 100.0, 249.15532313133338, 59.15532313133339, -0.0, -0.7071067811865475, -0.7071067811865475, 80.9447269211102, 51.428754043115056, 177.09583726797095]
133 }
134 partitionConeAndAssertShapeInfosEqual(PntMirroredCone, Prism, ExpectedPntMirroredConeFragmentsShapeInfos, False)
135
136 if salome.sg.hasDesktop():
137   salome.sg.updateObjBrowser()