Hide menu
Loading...
Searching...
No Matches
exploring/bom/bom.py
Refer to the Bill of Materials (BOM) Example.
1# $Id$
2
3# Copyright (C) 2008-2014, Roman Lygin. All rights reserved.
4# Copyright (C) 2014-2026, CADEX. All rights reserved.
5
6# This file is part of the Manufacturing Toolkit software.
7
8# You may use this file under the terms of the BSD license as follows:
9
10# Redistribution and use in source and binary forms, with or without
11# modification, are permitted provided that the following conditions are met:
12# * Redistributions of source code must retain the above copyright notice,
13# this list of conditions and the following disclaimer.
14# * Redistributions in binary form must reproduce the above copyright notice,
15# this list of conditions and the following disclaimer in the documentation
16# and/or other materials provided with the distribution.
17
18# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28# POSSIBILITY OF SUCH DAMAGE.
29
30
31import sys
32import os
33
34from pathlib import Path
35
36import mtk.MTKCore as mtk
37
38sys.path.append(os.path.abspath(os.path.dirname(Path(__file__).resolve()) + "/../../"))
39sys.path.append(os.path.abspath(os.path.dirname(Path(__file__).resolve()) + "/../../helpers/"))
40
41import LicenseHelper
42
43import mtk_license as license
44
45class SceneGraphVisitor(mtk.ModelData_ModelElementVoidVisitor):
46 def __init__(self):
47 super().__init__()
48 self.myNestingLevel = 0
49 self.margin = 0; # This variable is used for formatting of output table
50 self.myElementMap = {}
51
52 def PrintName(self, theElement: mtk.ModelData_ModelElement, theName: str):
53 print("--- " * self.myNestingLevel, end="")
54
55 if theName:
56 print(f"{theElement}: {theName}")
57 else:
58 print(f"{theElement}: noname")
59
60 # Calculating spacing for output table columns
61 self.margin = max(self.margin, theName.Length())
62
63 def UpdateTable(self, theElement: mtk.ModelData_ModelElement):
64 if not self.myElementMap.get(theElement):
65 self.myElementMap[theElement] = 1
66 else:
67 self.myElementMap[theElement] += 1
68
69 def PrintElementType(self, theElement: mtk.ModelData_ModelElement) -> str:
70 if mtk.ModelData_Part.CompareType(theElement):
71 return "Part"
72 elif mtk.ModelData_Assembly.CompareType(theElement):
73 return "Assembly"
74 elif mtk.ModelData_Instance.CompareType(theElement):
75 return "Instance"
76 return "Undefined"
77
78 def PrintCounts(self):
79 print("Total:")
80 print("\t" + "name".ljust(self.margin) + " | " + "type".ljust(self.margin) + " | count")
81
82 for i in self.myElementMap:
83 aName = str(i.Name())
84 aType = self.PrintElementType(i)
85 print("\t" + aName.ljust(self.margin) + " | " +
86 aType.ljust(self.margin) + " | " + str(self.myElementMap[i]))
87
88 def VisitPart(self, thePart: mtk.ModelData_Part):
89 self.PrintName("Part", thePart.Name())
90 self.UpdateTable(thePart)
91
92 def VisitEnterAssembly(self, theAssembly: mtk.ModelData_Assembly) -> bool:
93 self.PrintName("Assembly", theAssembly.Name())
94 self.UpdateTable(theAssembly)
95 self.myNestingLevel += 1
96 return True
97
98 def VisitEnterInstance(self, theInstance: mtk.ModelData_Instance) -> bool:
99 self.PrintName("Instance", theInstance.Name())
100 self.myNestingLevel += 1
101 return True
102
103 def VisitLeaveAssembly(self, theAssembly: mtk.ModelData_Assembly):
104 self.myNestingLevel -= 1
105
106 def VisitLeaveInstance(self, theInstance: mtk.ModelData_Instance):
107 self.myNestingLevel -= 1
108
109def main(theSource: str):
110 aKey = license.Value()
111
112 if not LicenseHelper.SetupRuntimeKey() :
113 return 1
114
115 try:
116 mtk.LicenseManager.Activate(aKey)
117 except mtk.LicenseError as anException:
118 mtk.LicenseManager.Deactivate()
119 print("Failed to activate Manufacturing Toolkit license: " + anException.what())
120 return 1
121
122 aModel = mtk.ModelData_Model()
123
124 if not mtk.ModelData_ModelReader().Read(mtk.UTF16String(theSource), aModel):
125 mtk.LicenseManager.Deactivate()
126 print("Failed to read the file " + theSource)
127 return 1
128
129 aVisitor = SceneGraphVisitor()
130
131 aModel.Accept(aVisitor)
132 aVisitor.PrintCounts()
133
134 print("Completed")
135
136 mtk.LicenseManager.Deactivate()
137
138 return 0
139
140if __name__ == "__main__":
141 if len(sys.argv) != 2:
142 print("Usage: " + os.path.abspath(Path(__file__).resolve()) + " <input_file>, where:")
143 print(" <input_file> is a name of the file to be read")
144 sys.exit()
145
146 aSource = os.path.abspath(sys.argv[1])
147
148 sys.exit(main(aSource))