Creating groups of shapes and adding them to parent partition (TUI vs GUI problems)

Hello,

I am trying to procedurally (Python TUI) create a group of faces and volumes for a complex geometry by adding them to parent partition.

Adding Solids groups work relatively well, although I noticed that I don’t always get the solids list in the same order (e.g. below, Solid_2 references Solid_3 object and vice versa ).

Structure = geompy.MakePartition([pml_bottom, pml_top, lens, air], [], [], [], geompy.ShapeType["SOLID"], 0, [], 0)

solids = [Solid_1, Solid_2, Solid_3, Solid_4] = geompy.ExtractShapes(Structure, geompy.ShapeType["SOLID"], True)

geompy.addToStudy(Structure, 'Structure')

This is a problem as I need to do everything procedurally and I can’t point and click to assign objects to variables.

Another problem that I am facing is when try to assign faces to a group and add it the parent partition. If try to do it procedurally I get a different set of faces than what I get via GUI. For example the code below

# SubFaceListAir = geompy.ExtractShapes(air, geompy.ShapeType["FACE"], True) 
# SubFaceListAir = geompy.SubShapeAll(air, geompy.ShapeType["FACE"]) 
SubFaceListAir = geompy.SubShapeAll(air, geompy.ShapeType["VERTEX"]) 
SubFaceListAirIDs = [ geompy.GetSubShapeID(air, sf) for sf in SubFaceListAir ]  
    
Group_Air_Faces = geompy.CreateGroup(Structure, geompy.ShapeType["FACE"]) 
  
geompy.UnionIDs(Group_Air_Faces, SubFaceListAirIDs) 

geompy.addToStudyInFather( Structure, Group_Air_Faces, 'Group_Air_Faces' )

generates a group ‘Group_Air_Faces’ with the following set of faces

If I try to do the same in the GUI, like so

I get the complete set of faces that I was expecting.

If I dump the script before and after the GUI operation, I find that the set of faces generated via TUI

Group_Air_Faces = geompy.CreateGroup(Structure, geompy.ShapeType["FACE"])

geompy.UnionIDs(Group_Air_Faces, [6, 7, 9, 11, 16, 18, 23, 27, 28, 30, 32, 36, 37, 39, 41, 45, 46, 48, 50, 54, 55, 57, 59, 63, 64, 66, 68, 72, 73, 75, 77, 81, 82, 84, 86, 90, 91, 93, 95, 100, 110, 111, 113, 115, 117, 119, 121, 123, 125, 127, 129, 131, 133, 135, 137, 139, 141, 143, 145, 147, 149, 151, 153, 155, 157, 159, 165, 170, 175, 177, 179, 181, 183, 185, 187, 189, 191, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 217, 219, 221, 226, 227, 229, 231, 233, 235, 237, 239, 241, 243, 245, 247, 249, 251, 253, 255, 257, 259, 261, 263, 265, 267, 269, 271, 273, 275, 281, 286, 291, 293, 295, 297, 299, 301, 303, 305, 307, 309, 311, 313, 315, 317, 319, 321, 323, 325, 327, 329, 331, 333, 335, 337, 342, 343, 345, 347, 349, 351, 353, 355, 357, 359, 361, 363, 365, 367, 369, 371, 373, 375, 377, 379, 381, 383, 385, 387, 389, 391, 397, 402, 407, 409, 411, 413, 415, 417, 419, 421, 423, 425, 427, 429, 431, 433, 435, 437, 439, 441, 443, 445, 447, 449, 451, 453, 458, 459, 461, 463, 465, 467, 469, 471, 473, 475, 477, 479, 481, 483, 485, 487, 489, 491, 493, 495, 497, 499, 501, 503, 505, 507, 513, 518, 523, 525, 527, 529, 531, 533, 535, 537, 539, 541, 543, 545, 547, 549, 551, 553, 555, 557, 559, 561, 563, 565, 567, 569, 574, 575, 577, 579, 581, 583, 585, 587, 589, 591, 593, 595, 597, 599, 601, 603, 605, 607, 609, 611, 613, 615, 617, 619, 621, 623, 629, 634, 639, 641, 643, 645, 647, 649, 651, 653, 655, 657, 659, 661, 663, 665, 667, 669, 671, 673, 675, 677, 679, 681, 683, 685, 690, 691, 693, 695, 697, 699, 701, 703, 705, 707, 709, 711, 713, 715, 717, 719, 721, 723, 725, 727, 729, 731, 733, 735, 737, 739, 745, 750, 755, 757, 759, 761, 763, 765, 767, 769, 771, 773, 775, 777, 779, 781, 783, 785, 787, 789, 791, 793, 795, 797, 799, 801, 806, 807, 809, 811, 813, 815, 817, 819, 821, 823, 825, 827, 829, 831, 833, 835, 837, 839, 841, 843, 845, 847, 849, 851, 853, 855, 861, 866, 871, 873, 875, 877, 879, 881, 883, 885, 887, 889, 891, 893, 895, 897, 899, 901, 903, 905, 907, 909, 911, 913, 915, 917, 922, 923, 925, 927, 929, 931, 933, 935, 937, 939, 941, 943, 945, 947, 949, 951, 953, 955, 957, 959, 961, 963, 965, 967, 969, 971, 977, 982, 984, 986, 988, 990, 992, 994, 996, 998, 1000, 1002, 1004, 1006, 1008, 1010, 1012, 1014, 1016, 1018, 1020, 1022, 1024, 1026, 1028, 1030, 1074, 1075, 1077, 1079, 1632, 1634, 1639, 1644])

is different from the set generated via GUI

Group_Air_Faces_GUI = geompy.CreateGroup(Structure, geompy.ShapeType["FACE"])
geompy.UnionIDs(Group_Air_Faces_GUI, [1015, 1018, 1025, 34, 66, 1075, 1080, 89, 1128, 1131, 1134, 1137, 1140, 1143, 1146, 1149, 1152, 1155, 1158, 1161, 1164, 1167, 1170, 1173, 1176, 1179, 171, 1182, 1185, 1188, 1191, 1194, 1197, 1200, 1203, 1206, 1208, 1211, 1214, 1217, 1220, 1223, 1226, 1229, 1232, 1235, 1238, 1240, 1243, 1246, 1249, 1252, 1255, 248, 1258, 1261, 255, 1264, 1267, 1270, 1272, 1275, 1278, 1281, 1284, 1287, 1290, 1293, 1296, 1299, 1302, 1304, 1307, 1310, 1313, 305, 1316, 1319, 1322, 1325, 1328, 1331, 1334, 1336, 1339, 1342, 1345, 1348, 1351, 1354, 1357, 1360, 1363, 355, 1366, 358, 1368, 1371, 1374, 365, 1377, 1380, 1383, 1386, 1389, 1392, 1395, 1398, 1400, 1403, 1406, 1409, 1412, 1415, 1418, 1421, 1424, 415, 1427, 1430, 1432, 1435, 1438, 1441, 1444, 1447, 1450, 1453, 1456, 1459, 1462, 1464, 1467, 1470, 1473, 465, 1476, 468, 1479, 1482, 475, 1485, 1488, 1491, 1494, 1496, 1499, 1502, 1505, 1508, 1511, 1514, 1517, 1520, 1523, 1526, 1528, 1531, 1534, 525, 1537, 1540, 1543, 1546, 1549, 1552, 1555, 1558, 1560, 1563, 1566, 1569, 1572, 1575, 1578, 1581, 1584, 575, 1587, 578, 1590, 1592, 585, 1595, 1598, 1601, 1604, 1607, 1610, 1613, 1616, 1619, 1622, 1624, 1627, 1630, 1633, 1636, 1639, 1642, 635, 1645, 1648, 1651, 1654, 1656, 1659, 1662, 1665, 1668, 1671, 1674, 1677, 1680, 1683, 1686, 1690, 685, 1694, 688, 1697, 1700, 1702, 695, 1706, 1709, 1712, 745, 795, 798, 805, 855, 905, 908, 915, 965])

So my questions are:

a) What is missing from my code in order to obtain the same results in terms of faces via TUI as I do via GUI?

b) How do I ensure that in ExtractShape operations I obtain a list of objects consistently ordered?

Many thanks,
Francisco

Best,
Francisco

Answering my own question b) how to ensure that ExtractShape obtain a list of objects consistently ordered?

Well I found out that neither ExtractShape nor SubShapeAllSortedCentres return a consistently ordered list.

E.g. when the script loads, the four objects referenced by the list of solids below reference, can come up in different order.

  Structure = geompy.MakePartition([pml_bottom, pml_top, lens, air], [], [], [], geompy.ShapeType["SOLID"], 0, [], 0)
  geompy.addToStudy( Structure, 'Structure' )
  
  # solids = [Solid_1, Solid_2, Solid_3, Solid_4] = geompy.ExtractShapes(Structure, geompy.ShapeType["SOLID"], True)
  solids = [Solid_1, Solid_2, Solid_3, Solid_4] = geompy.SubShapeAllSortedCentres(Structure, geompy.ShapeType["SOLID"])

So we need to sort the solids based on some attribute that we know about our use case. In my case, I know the relative order of the solids’ center of mass which I used to ensure the order of the objects.

  # sort by Z coordinate of the center of mass of the solid, an attribute of the solid object  
  solids_sorted = sorted(solids, key=lambda s: geompy.PointCoordinates(geompy.MakeCDG(s))[2] )

  # expand ordered list and assign to objects for futher processing
  [ solid_pml_inlet, solid_lens, solid_air, solid_pml_outlet ] = solids_sorted

Still, I would expect that a method named SubShapeAllSortedCentres to implement this functionality.

1 Like

Answering my own question a) on how to assign faces to a group and add it to the parent partition and have consistent results between TUI and GUI in terms of groups and faces that are added to the geometry and mesh.

I found that extracting faces of solids from a partition, grouping them, and doing boolean operations with the groups seems to garantee consistency.

So for instance, taking the ordered list of solids from the previous answer, I can get shared faces between two of the solids, group them and add them to the father

shared_faces_lens_solid_air = geompy.GetSharedShapesMulti( [ solid_lens, solid_air ],  geompy.ShapeType['FACE'], False) 

group_faces_air_lens = geompy.CreateGroup(Structure, geompy.ShapeType["FACE"])

geompy.UnionList(group_faces_air_lens, shared_faces_lens_solid_air )

geompy.addToStudyInFather( Structure, group_faces_air_lens, 'group_faces_air_lens' )

Another approach that I found useful was hinted by @cbourcier in this thread. Essentially, if you know a point of a face, you can use that point to extract the face and group it with other faces and add them to the father.

face_pml_inlet_left = geompy.GetFaceNearPoint(group_faces_pml_inlet,    geompy.MakeVertex(0, -0.108263, 1.2865))
face_air_left_1 = geompy.GetFaceNearPoint(group_faces_air,              geompy.MakeVertex(0, -0.108263, 57.761))
face_air_left_2 = geompy.GetFaceNearPoint(group_faces_air,              geompy.MakeVertex(0, -0.108263, 4.717))
face_pml_outlet_left = geompy.GetFaceNearPoint(group_faces_pml_outlet,  geompy.MakeVertex(0, -0.108263, 101.2865))

group_faces_air_left = geompy.CreateGroup(Structure, geompy.ShapeType["FACE"])
geompy.UnionList( group_faces_air_left, [face_air_left_1, face_air_left_2, face_pml_inlet_left, face_pml_outlet_left] )
geompy.addToStudyInFather(Structure, group_faces_air_left, 'group_faces_left' )

In order for the groups to appear in the mesh you need to create the Smesh object and add it

mesh_air_left = Structure_1.GroupOnGeom( group_faces_air_left, 'left', SMESH.FACE)

Hello francisco,
another option you have that I use when trying to automate things, is to use planes which is similar to the cbourcier approach. one thing that I would add, at least in my case is to extract the already created groups. for example in my case, I have a geometry that is an hexagon with several internal faces that are difficult to select. what I did was create a group for each face, and another that contains everything and then took out the faces that are in the other groups (so the last groups contains everything that is not in the rest of the groups)

[xMinTotal,xMaxTotal, yMinTotal,yMaxTotal, zMinTotal,zMaxTotal] = geompy.BoundingBox(fluid, True)
MAXdistance=numpy.max([xMaxTotal-xMinTotal,yMaxTotal-yMinTotal,zMaxTotal-zMinTotal])
Plane_1 = geompy.MakePlane(Vertex_3_box,  OX, MAXdistance*10) #inlet
Plane_2 = geompy.MakePlane(Vertex_4_box,  OX, MAXdistance*10) #outlet
Plane_3 = geompy.MakePlane(Vertex_3_box,  OZ, MAXdistance*10) #plane XY with Zpos
Plane_4 = geompy.MakePlane(Vertex_3_box,  OY, MAXdistance*10) #plane XZ with Ypos
Plane_5 = geompy.MakePlane(Vertex_4_box,  OZ, MAXdistance*10) #plane XY with Zneg
Plane_6 = geompy.MakePlane(Vertex_4_box,  OY, MAXdistance*10) #plane XZ with Yneg

geomObj_1 = geompy.GetInPlace(fluid, Plane_1, True)
geomObj_2 = geompy.GetInPlace(fluid, Plane_2, True)
geomObj_3 = geompy.GetInPlace(fluid, Plane_3, True)
geomObj_4 = geompy.GetInPlace(fluid, Plane_4, True)
geomObj_5 = geompy.GetInPlace(fluid, Plane_5, True)
geomObj_6 = geompy.GetInPlace(fluid, Plane_6, True)
geomObj_7 = geompy.SubShapeAll(fluid, geompy.ShapeType["FACE"])

Group_1 = geompy.CreateGroup(fluid, geompy.ShapeType["FACE"])
geompy.UnionList(Group_1, [geomObj_1])

Group_2 = geompy.CreateGroup(fluid, geompy.ShapeType["FACE"])
geompy.UnionList(Group_2, [geomObj_2])

Group_3 = geompy.CreateGroup(fluid, geompy.ShapeType["FACE"])
geompy.UnionList(Group_3, [geomObj_3])

Group_4 = geompy.CreateGroup(fluid, geompy.ShapeType["FACE"])
geompy.UnionList(Group_4, [geomObj_4])

Group_5 = geompy.CreateGroup(fluid, geompy.ShapeType["FACE"])
geompy.UnionList(Group_5, [geomObj_5])

Group_6 = geompy.CreateGroup(fluid, geompy.ShapeType["FACE"])
geompy.UnionList(Group_6, [geomObj_6])

Group_7 = geompy.CreateGroup(fluid, geompy.ShapeType["FACE"])
geompy.UnionList(Group_7, geomObj_7)
geompy.DifferenceList(Group_7, [geomObj_1, geomObj_2, geomObj_3, geomObj_4, geomObj_5, geomObj_6])

this approach might also help :slight_smile: best regards

1 Like

thanks @franco.ota that will be helpful!