Hide menu
Loading...
Searching...
No Matches
machining/dfm_analyzer/dfm_analyzer.py

Refer to the CNC Machining DFM Analyzer Example

feature_group.py

1# $Id$
2#
3# Copyright (C) 2008-2014, Roman Lygin. All rights reserved.
4# Copyright (C) 2014-2025, 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
30from functools import cmp_to_key
31
32import manufacturingtoolkit.CadExMTK as mtk
33
34class Pair:
35 def __init__(self, theFirst: float, theSecond: float):
36 self.First = theFirst
37 self.Second = theSecond
38
39 def __repr__(self):
40 return f"Pair({self.First}, {self.Second})"
41
42 def __str__(self):
43 return f"{self.First:.5f} x {self.Second:.5f}"
44
45class Dimension:
46 def __init__(self, theX: float, theY: float, theZ: float):
47 self.X = theX
48 self.Y = theY
49 self.Z = theZ
50
51 def __repr__(self):
52 return f"Dimension({self.X}, {self.Y}, {self.Z})"
53
54 def __str__(self):
55 return f"{self.X:.5f} x {self.Y:.5f} x {self.Z:.5f}"
56
57class Direction:
58 def __init__(self, theX: float, theY: float, theZ: float):
59 self.X = theX
60 self.Y = theY
61 self.Z = theZ
62
63 def __repr__(self):
64 return f"Direction({self.X}, {self.Y}, {self.Z})"
65
66 def __str__(self):
67 return f"({self.X:.2f}, {self.Y:.2f}, {self.Z:.2f})"
68
69def CompareFeatures(theA: mtk.MTKBase_Feature, theB: mtk.MTKBase_Feature):
70 aComparator = mtk.MTKBase_FeatureComparator()
71 anALessThanB = aComparator(theA, theB)
72 if anALessThanB:
73 return -1
74
75 aBLessThanA = aComparator(theB, theA)
76 if aBLessThanA:
77 return 1
78
79 return 0
80
81class FeatureGroupManager:
82 def __init__(self):
83 self.__myGroups = []
84
85 def AddFeature(self, theGroupName: str, theSubgroupName: str, theHasParameters: bool, theFeature: mtk.MTKBase_Feature):
86 #find or create
87 aRes = -1
88 for i in range(len(self.__myGroups)):
89 aGroup = self.__myGroups[i]
90 if aGroup.myName == theGroupName:
91 aRes = i
92 break
93
94 if aRes == -1:
95 self.__myGroups.append(self.FeatureGroup(theGroupName, theSubgroupName, theHasParameters))
96 aRes = len(self.__myGroups) - 1
97
98 #update
99 aGroup = self.__myGroups[aRes]
100 aSubgroups = aGroup.myFeatureSubgroups
101 aSubgroups.Append(theFeature)
102
103 def Print(self, theFeatureType: str, thePrintFeatureParameters):
104 self.__myGroups.sort(key=cmp_to_key(self.__compare))
105
106 aTotalCount = 0
107 for i in self.__myGroups:
108 aFeatureCount = i.FeatureCount()
109 aTotalCount += aFeatureCount
110
111 print(" ", i.myName, ": ", aFeatureCount, sep="")
112
113 if not i.myHasParameters:
114 continue
115
116 aSubgroupName = i.mySubgroupName
117 for j in range(i.myFeatureSubgroups.Size()):
118 print(" ", i.myFeatureSubgroups.GetFeatureCount(j), " ", aSubgroupName, " with", sep="")
119 thePrintFeatureParameters(i.myFeatureSubgroups.GetFeature(j))
120
121 print("\n Total ", theFeatureType, ": ", aTotalCount, "\n", sep="")
122
123 @staticmethod
124 def PrintFeatureParameter(theName: str, theValue, theUnits: str):
125 print(" ", theName, ": ", theValue, " ", theUnits, sep = "")
126
127 class OrderedFeatureList:
128 def __init__(self):
129 self.__myList = []
130
131 def Append(self, theFeature: mtk.MTKBase_Feature):
132 anInsertIndex = 0
133 for i in self.__myList:
134 aRes = CompareFeatures(theFeature, i.Feature)
135 if aRes == 0:
136 i.Count += 1
137 anInsertIndex = -1
138 break
139 elif aRes < 0:
140 break
141
142 anInsertIndex += 1
143
144 if anInsertIndex >= 0:
145 self.__myList.insert(anInsertIndex, self.FeatureAndCountPair(theFeature))
146
147 def Size(self):
148 return len(self.__myList)
149
150 def GetFeature(self, theIndex: int):
151 return self.__GetFeatureAndCountPair(theIndex).Feature
152
153 def GetFeatureCount(self, theIndex: int):
154 return self.__GetFeatureAndCountPair(theIndex).Count
155
156 def __GetFeatureAndCountPair(self, theIndex: int):
157 return self.__myList[theIndex]
158
159 class FeatureAndCountPair:
160 def __init__(self, theFeature: mtk.MTKBase_Feature):
161 self.Feature = theFeature
162 self.Count = 1
163
164 class FeatureGroup:
165 def __init__(self, theName: str, theSubgroupName: str, theHasParameters: bool):
166 self.myName = theName
167 self.mySubgroupName = theSubgroupName
168 self.myHasParameters = theHasParameters
169 self.myFeatureSubgroups = FeatureGroupManager.OrderedFeatureList()
170
171 def FeatureCount(self):
172 aCount = 0
173 for i in range(self.myFeatureSubgroups.Size()):
174 aCount += self.myFeatureSubgroups.GetFeatureCount(i)
175 return aCount
176
177 @staticmethod
178 def __compare(theA: FeatureGroup, theB: FeatureGroup):
179 anAName = theA.myName
180 aBName = theB.myName
181 if anAName == aBName:
182 return 0
183
184 anAFeatureSubgroups = theA.myFeatureSubgroups
185 aBFeatureSubgroups = theB.myFeatureSubgroups
186 if (not anAFeatureSubgroups) or (not aBFeatureSubgroups):
187 if anAName < aBName:
188 return -1
189 else:
190 return 1
191
192 anAFeature = anAFeatureSubgroups.GetFeature(0)
193 aBFeature = aBFeatureSubgroups.GetFeature(0)
194 return CompareFeatures(anAFeature, aBFeature)

shape_processor.py

1# $Id$
2#
3# Copyright (C) 2008-2014, Roman Lygin. All rights reserved.
4# Copyright (C) 2014-2025, 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
30from abc import abstractmethod
31
32import manufacturingtoolkit.CadExMTK as mtk
33
34class ShapeProcessor(mtk.ModelData_ModelElementVoidVisitor):
35 def __init__(self):
36 super().__init__()
37 self.myPartIndex = 0
38
39 def VisitPart(self, thePart: mtk.ModelData_Part):
40 aPartName = "noname" if thePart.Name().IsEmpty() else thePart.Name()
41
42 aBodyList = thePart.Bodies()
43 i = 0
44 for aBody in aBodyList:
45 aShapeIt = mtk.ModelData_ShapeIterator(aBody)
46 for aShape in aShapeIt:
47 if aShape.Type() == mtk.ShapeType_Solid:
48 print("Part #", self.myPartIndex, " [\"", aPartName, "\"] - solid #", i, " has:", sep="")
49 i += 1
50 self.ProcessSolid(mtk.ModelData_Solid.Cast(aShape))
51 elif aShape.Type() == mtk.ShapeType_Shell:
52 print("Part #", self.myPartIndex, " [\"", aPartName, "\"] - shell #", i, " has:", sep="")
53 i += 1
54 self.ProcessShell(mtk.ModelData_Shell.Cast (aShape))
55 self.myPartIndex += 1
56
57 @abstractmethod
58 def ProcessSolid(self, theSolid: mtk.ModelData_Solid):
59 pass
60
61 @abstractmethod
62 def ProcessShell(self, theShell: mtk.ModelData_Shell):
63 pass
64
65class SolidProcessor(mtk.ModelData_ModelElementVoidVisitor):
66 def __init__(self):
67 super().__init__()
68 self.myPartIndex = 0
69
70 def VisitPart(self, thePart: mtk.ModelData_Part):
71 aPartName = "noname" if thePart.Name().IsEmpty() else thePart.Name()
72
73 aBodyList = thePart.Bodies()
74 i = 0
75 for aBody in aBodyList:
76 aShapeIt = mtk.ModelData_ShapeIterator(aBody)
77 for aShape in aShapeIt:
78 if aShape.Type() == mtk.ShapeType_Solid:
79 print("Part #", self.myPartIndex, " [\"", aPartName, "\"] - solid #", i, " has:", sep="")
80 i += 1
81 self.ProcessSolid (mtk.ModelData_Solid.Cast (aShape))
82 self.myPartIndex += 1
83
84 @abstractmethod
85 def ProcessSolid(self, theSolid: mtk.ModelData_Solid):
86 pass

dfm_analyzer.py

1# $Id$
2#
3# Copyright (C) 2008-2014, Roman Lygin. All rights reserved.
4# Copyright (C) 2014-2025, 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
30import math
31import os
32import sys
33
34from pathlib import Path
35
36import manufacturingtoolkit.CadExMTK 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 mtk_license as license
42
43import feature_group
44import shape_processor
45
46def ToDegrees(theAngleRad: float):
47 return theAngleRad * 180.0 / math.pi
48
49def PrintFeatureParameters(theIssue: mtk.MTKBase_Feature):
50 #drilling
51 if mtk.DFMMachining_SmallDiameterHoleIssue.CompareType(theIssue):
52 aSDHIssue = mtk.DFMMachining_SmallDiameterHoleIssue.Cast(theIssue)
53 feature_group.FeatureGroupManager.PrintFeatureParameter("expected min diameter", aSDHIssue.ExpectedMinDiameter(), "mm")
54 feature_group.FeatureGroupManager.PrintFeatureParameter("actual diameter", aSDHIssue.ActualDiameter(), "mm")
55 elif mtk.DFMMachining_DeepHoleIssue.CompareType(theIssue):
56 aDHIssue = mtk.DFMMachining_DeepHoleIssue.Cast(theIssue)
57 feature_group.FeatureGroupManager.PrintFeatureParameter("expected max depth", aDHIssue.ExpectedMaxDepth(), "mm")
58 feature_group.FeatureGroupManager.PrintFeatureParameter("actual depth", aDHIssue.ActualDepth(), "mm")
59 elif mtk.DFMMachining_NonStandardDiameterHoleIssue.CompareType(theIssue):
60 aNSDHIssue = mtk.DFMMachining_NonStandardDiameterHoleIssue.Cast(theIssue)
61 feature_group.FeatureGroupManager.PrintFeatureParameter("nearest standard diameter", aNSDHIssue.NearestStandardDiameter(), "mm")
62 feature_group.FeatureGroupManager.PrintFeatureParameter("actual diameter", aNSDHIssue.ActualDiameter(), "mm")
63 elif mtk.DFMMachining_NonStandardDrillPointAngleBlindHoleIssue.CompareType(theIssue):
64 aNSDPABHIssue = mtk.DFMMachining_NonStandardDrillPointAngleBlindHoleIssue.Cast(theIssue)
65 feature_group.FeatureGroupManager.PrintFeatureParameter("nearest standard angle", ToDegrees(aNSDPABHIssue.NearestStandardAngle()), "deg")
66 feature_group.FeatureGroupManager.PrintFeatureParameter("actual angle", ToDegrees(aNSDPABHIssue.ActualAngle()), "deg")
67 elif mtk.DFMMachining_FlatBottomHoleIssue.CompareType(theIssue):
68 pass #no parameters
69 elif mtk.DFMMachining_NonPerpendicularHoleIssue.CompareType(theIssue):
70 pass #no parameters
71 elif mtk.DFMMachining_IntersectingCavityHoleIssue.CompareType(theIssue):
72 pass #no parameters
73 elif mtk.DFMMachining_PartialHoleIssue.CompareType(theIssue):
74 aPHIssue = mtk.DFMMachining_PartialHoleIssue.Cast(theIssue)
75 feature_group.FeatureGroupManager.PrintFeatureParameter(
76 "expected min material percent", aPHIssue.ExpectedMinMaterialPercent(), "")
77 feature_group.FeatureGroupManager.PrintFeatureParameter(
78 "actual material percent", aPHIssue.ActualMaterialPercent(), "")
79 #milling
80 elif mtk.DFMMachining_NonStandardRadiusMilledPartFloorFilletIssue.CompareType(theIssue):
81 aNSRMPFFIssue = mtk.DFMMachining_NonStandardRadiusMilledPartFloorFilletIssue.Cast(theIssue)
82 feature_group.FeatureGroupManager.PrintFeatureParameter("nearest standard radius", aNSRMPFFIssue.NearestStandardRadius(), "mm")
83 feature_group.FeatureGroupManager.PrintFeatureParameter("actual radius", aNSRMPFFIssue.ActualRadius(), "mm")
84 elif mtk.DFMMachining_DeepPocketIssue.CompareType(theIssue):
85 aDPIssue = mtk.DFMMachining_DeepPocketIssue.Cast(theIssue)
86 feature_group.FeatureGroupManager.PrintFeatureParameter("expected max depth", aDPIssue.ExpectedMaxDepth(), "mm")
87 feature_group.FeatureGroupManager.PrintFeatureParameter("actual depth", aDPIssue.ActualDepth(), "mm")
88 elif mtk.DFMMachining_HighBossIssue.CompareType(theIssue):
89 aHBIssue = mtk.DFMMachining_HighBossIssue.Cast(theIssue)
90 feature_group.FeatureGroupManager.PrintFeatureParameter("expected max height", aHBIssue.ExpectedMaxHeight(), "mm")
91 feature_group.FeatureGroupManager.PrintFeatureParameter("actual height", aHBIssue.ActualHeight(), "mm")
92 elif mtk.DFMMachining_LargeMilledPartIssue.CompareType(theIssue):
93 aLMPIssue = mtk.DFMMachining_LargeMilledPartIssue.Cast(theIssue)
94 anExpectedSize = aLMPIssue.ExpectedMaxMilledPartSize()
95 anActualSize = aLMPIssue.ActualMilledPartSize()
96 feature_group.FeatureGroupManager.PrintFeatureParameter(
97 "expected max size (LxWxH)",
98 feature_group.Dimension(anExpectedSize.Length(), anExpectedSize.Width(), anExpectedSize.Height()),
99 "mm")
100 feature_group.FeatureGroupManager.PrintFeatureParameter(
101 "actual size (LxWxH)",
102 feature_group.Dimension(anActualSize.Length(), anActualSize.Width(), anActualSize.Height()),
103 "mm")
104 elif mtk.DFMMachining_SmallRadiusMilledPartInternalCornerIssue.CompareType(theIssue):
105 aSRMPICIssue = mtk.DFMMachining_SmallRadiusMilledPartInternalCornerIssue.Cast(theIssue)
106 feature_group.FeatureGroupManager.PrintFeatureParameter("expected min radius", aSRMPICIssue.ExpectedMinRadius(), "mm")
107 feature_group.FeatureGroupManager.PrintFeatureParameter("actual radius", aSRMPICIssue.ActualRadius(), "mm")
108 elif mtk.DFMMachining_NonPerpendicularMilledPartShapeIssue.CompareType(theIssue):
109 aNPMPSIssue = mtk.DFMMachining_NonPerpendicularMilledPartShapeIssue.Cast(theIssue)
110 feature_group.FeatureGroupManager.PrintFeatureParameter("actual angle", ToDegrees (aNPMPSIssue.ActualAngle()), "deg")
111 elif mtk.DFMMachining_MilledPartExternalEdgeFilletIssue.CompareType(theIssue):
112 pass #no parameters
113 elif mtk.DFMMachining_InconsistentRadiusMilledPartFloorFilletIssue.CompareType(theIssue):
114 aIRMPFFIssue = mtk.DFMMachining_InconsistentRadiusMilledPartFloorFilletIssue.Cast(theIssue)
115 feature_group.FeatureGroupManager.PrintFeatureParameter("expected radius", aIRMPFFIssue.ExpectedRadius(), "mm")
116 feature_group.FeatureGroupManager.PrintFeatureParameter("actual radius", aIRMPFFIssue.ActualRadius(), "mm")
117 elif mtk.DFMMachining_NarrowRegionInPocketIssue.CompareType(theIssue):
118 aSMNRDIssue = mtk.DFMMachining_NarrowRegionInPocketIssue.Cast(theIssue)
119 feature_group.FeatureGroupManager.PrintFeatureParameter("expected minimum region size", aSMNRDIssue.ExpectedMinRegionSize(), "mm")
120 feature_group.FeatureGroupManager.PrintFeatureParameter("actual region size", aSMNRDIssue.ActualRegionSize(), "mm")
121 elif mtk.DFMMachining_LargeDifferenceRegionsSizeInPocketIssue.CompareType(theIssue):
122 aLMNRRIssue = mtk.DFMMachining_LargeDifferenceRegionsSizeInPocketIssue.Cast(theIssue)
123 feature_group.FeatureGroupManager.PrintFeatureParameter("expected regions maximum to minimum size ratio", aLMNRRIssue.ExpectedMaxRegionsMaxToMinSizeRatio(), "")
124 feature_group.FeatureGroupManager.PrintFeatureParameter("actual regions maximum to minimum size ratio", aLMNRRIssue.ActualMaxRegionsMaxToMinSizeRatio(), "")
125 elif mtk.DFMMachining_SmallWallThicknessIssue.CompareType(theIssue):
126 aSWTIssue = mtk.DFMMachining_SmallWallThicknessIssue.Cast(theIssue)
127 feature_group.FeatureGroupManager.PrintFeatureParameter("expected min wall thickness", aSWTIssue.ExpectedMinThickness(), "mm")
128 feature_group.FeatureGroupManager.PrintFeatureParameter("actual wall thickness", aSWTIssue.ActualThickness(), "mm")
129 #turning
130 elif mtk.DFMMachining_IrregularTurnedPartOuterDiameterProfileReliefIssue.CompareType(theIssue):
131 anITPODPRIssue = mtk.DFMMachining_IrregularTurnedPartOuterDiameterProfileReliefIssue.Cast(theIssue)
132 feature_group.FeatureGroupManager.PrintFeatureParameter(
133 "expected max incline angle", ToDegrees (anITPODPRIssue.ExpectedMaxFaceInclineAngle()), "deg")
134 feature_group.FeatureGroupManager.PrintFeatureParameter(
135 "actual incline angle", ToDegrees (anITPODPRIssue.ActualFaceInclineAngle()), "deg")
136 elif mtk.DFMMachining_SmallRadiusTurnedPartInternalCornerIssue.CompareType(theIssue):
137 aSRTPICIssue = mtk.DFMMachining_SmallRadiusTurnedPartInternalCornerIssue.Cast(theIssue)
138 feature_group.FeatureGroupManager.PrintFeatureParameter("expected min radius", aSRTPICIssue.ExpectedMinRadius(), "mm")
139 feature_group.FeatureGroupManager.PrintFeatureParameter("actual radius", aSRTPICIssue.ActualRadius(), "mm")
140 elif mtk.DFMMachining_LargeTurnedPartIssue.CompareType(theIssue):
141 aLTPIssue = mtk.DFMMachining_LargeTurnedPartIssue.Cast(theIssue)
142 anExpectedSize = aLMPIssue.ExpectedMaxTurnedPartSize()
143 anActualSize = aLMPIssue.ActualTurnedPartSize()
144 feature_group.FeatureGroupManager.PrintFeatureParameter(
145 "expected max size (LxR)",
146 feature_group.Pair(anExpectedSize.Length(), anExpectedSize.Radius()),
147 "mm")
148 feature_group.FeatureGroupManager.PrintFeatureParameter(
149 "actual size (LxR)",
150 feature_group.Pair(anActualSize.Length(), anActualSize.Radius()),
151 "mm")
152 elif mtk.DFMMachining_LongSlenderTurnedPartIssue.CompareType(theIssue):
153 aLSTPIssue = mtk.DFMMachining_LongSlenderTurnedPartIssue.Cast(theIssue)
154 feature_group.FeatureGroupManager.PrintFeatureParameter("expected min length", aLSTPIssue.ExpectedMaxLength(), "mm")
155 feature_group.FeatureGroupManager.PrintFeatureParameter("actual length", aLSTPIssue.ActualLength(), "mm")
156 feature_group.FeatureGroupManager.PrintFeatureParameter("actual min diameter", aLSTPIssue.ActualMinDiameter(), "mm")
157 elif mtk.DFMMachining_SmallDepthBlindBoredHoleReliefIssue.CompareType(theIssue):
158 aSDBBHRIssue = mtk.DFMMachining_SmallDepthBlindBoredHoleReliefIssue.Cast(theIssue)
159 feature_group.FeatureGroupManager.PrintFeatureParameter(
160 "expected min relief depth", aSDBBHRIssue.ExpectedMinReliefDepth(), "mm")
161 feature_group.FeatureGroupManager.PrintFeatureParameter(
162 "actual relief depth", aSDBBHRIssue.ActualReliefDepth(), "mm")
163 feature_group.FeatureGroupManager.PrintFeatureParameter(
164 "actual diameter", aSDBBHRIssue.ActualDiameter(), "mm")
165 elif mtk.DFMMachining_DeepBoredHoleIssue.CompareType(theIssue):
166 aDBHIssue = mtk.DFMMachining_DeepBoredHoleIssue.Cast(theIssue)
167 feature_group.FeatureGroupManager.PrintFeatureParameter("expected max depth", aDBHIssue.ExpectedMaxDepth(), "mm")
168 feature_group.FeatureGroupManager.PrintFeatureParameter("actual depth", aDBHIssue.ActualDepth(), "mm")
169 feature_group.FeatureGroupManager.PrintFeatureParameter("actual diameter", aDBHIssue.ActualDiameter(), "mm")
170 elif mtk.DFMMachining_SquareEndKeywayIssue.CompareType(theIssue):
171 pass #no parameters
172 elif mtk.DFMMachining_NonSymmetricalAxialSlotIssue.CompareType(theIssue):
173 pass #no parameters
174
175def PrintIssues(theIssueList: mtk.MTKBase_FeatureList):
176 aManager = feature_group.FeatureGroupManager()
177
178 #group by parameters to provide more compact information about features
179 for anIssue in theIssueList:
180 #drilling
181 if mtk.DFMMachining_SmallDiameterHoleIssue.CompareType(anIssue):
182 aManager.AddFeature("Small Diameter Hole Issue(s)", "Hole(s)", True, anIssue)
183 elif mtk.DFMMachining_DeepHoleIssue.CompareType(anIssue):
184 aManager.AddFeature("Deep Hole Issue(s)", "Hole(s)", True, anIssue)
185 elif mtk.DFMMachining_NonStandardDiameterHoleIssue.CompareType(anIssue):
186 aManager.AddFeature("Non Standard Diameter Hole Issue(s)", "Hole(s)", True, anIssue)
187 elif mtk.DFMMachining_NonStandardDrillPointAngleBlindHoleIssue.CompareType(anIssue):
188 aManager.AddFeature("Non Standard Drill Point Angle Blind Hole Issue(s)", "Hole(s)", True, anIssue)
189 elif mtk.DFMMachining_FlatBottomHoleIssue.CompareType(anIssue):
190 aManager.AddFeature("Flat Bottom Hole Issue(s)", "", False, anIssue)
191 elif mtk.DFMMachining_NonPerpendicularHoleIssue.CompareType(anIssue):
192 aManager.AddFeature("Non Perpendicular Hole Issue(s)", "", False, anIssue)
193 elif mtk.DFMMachining_IntersectingCavityHoleIssue.CompareType(anIssue):
194 aManager.AddFeature("Intersecting Cavity Hole Issue(s)", "", False, anIssue)
195 elif mtk.DFMMachining_PartialHoleIssue.CompareType(anIssue):
196 aManager.AddFeature("Partial Hole Issue(s)", "Hole(s)", True, anIssue)
197 #milling
198 elif mtk.DFMMachining_NonStandardRadiusMilledPartFloorFilletIssue.CompareType(anIssue):
199 aManager.AddFeature("Non Standard Radius Milled Part Floor Fillet Issue(s)", "Floor Fillet(s)", True, anIssue)
200 elif mtk.DFMMachining_DeepPocketIssue.CompareType(anIssue):
201 aManager.AddFeature("Deep Pocket Issue(s)", "Pocket(s)", True, anIssue)
202 elif mtk.DFMMachining_DeepPocketIssue.CompareType(anIssue):
203 aManager.AddFeature("High Boss Issue(s)", "Boss(es)", True, anIssue)
204 elif mtk.DFMMachining_LargeMilledPartIssue.CompareType(anIssue):
205 aManager.AddFeature("Large Milled Part Issue(s)", "Part(s)", True, anIssue)
206 elif mtk.DFMMachining_SmallRadiusMilledPartInternalCornerIssue.CompareType(anIssue):
207 aManager.AddFeature("Small Radius Milled Part Internal Corner Issue(s)", "Internal Corner(s)", True, anIssue)
208 elif mtk.DFMMachining_NonPerpendicularMilledPartShapeIssue.CompareType(anIssue):
209 aManager.AddFeature("Non Perpendicular Milled Part Shape Issue(s)", "Shape(s)", True, anIssue)
210 elif mtk.DFMMachining_MilledPartExternalEdgeFilletIssue.CompareType(anIssue):
211 aManager.AddFeature("Milled Part External Edge Fillet Issue(s)", "", False, anIssue)
212 elif mtk.DFMMachining_InconsistentRadiusMilledPartFloorFilletIssue.CompareType(anIssue):
213 aManager.AddFeature("Inconsistent Radius Milled Part Floor Fillet Issue(s)", "Floor Fillet(s)", True, anIssue)
214 elif mtk.DFMMachining_NarrowRegionInPocketIssue.CompareType(anIssue):
215 aManager.AddFeature("Narrow Region In Pocket Issue(s)", "Region(s)", True, anIssue)
216 elif mtk.DFMMachining_LargeDifferenceRegionsSizeInPocketIssue.CompareType(anIssue):
217 aManager.AddFeature("Large Difference Regions Size In Pocket Issue(s)", "Region Size(s)", True, anIssue)
218 elif mtk.DFMMachining_SmallWallThicknessIssue.CompareType(anIssue):
219 aManager.AddFeature("Small Wall Thickness Issue(s)", "Wall(s)", True, anIssue)
220 #turning
221 elif mtk.DFMMachining_IrregularTurnedPartOuterDiameterProfileReliefIssue.CompareType(anIssue):
222 aManager.AddFeature("Irregular Turned Part Outer Diameter Profile Relief Issue(s)", "Outer Diameter Profile Relief(s)", True, anIssue)
223 elif mtk.DFMMachining_SmallRadiusTurnedPartInternalCornerIssue.CompareType(anIssue):
224 aManager.AddFeature("Small Radius Turned Part Internal Corner Issue(s)", "Internal Corner(s)", True, anIssue)
225 elif mtk.DFMMachining_LargeTurnedPartIssue.CompareType(anIssue):
226 aManager.AddFeature("Large Turned Part Issue(s)", "Part(s)", True, anIssue)
227 elif mtk.DFMMachining_LongSlenderTurnedPartIssue.CompareType(anIssue):
228 aManager.AddFeature("Long Slender Turned Part Issue(s)", "Part(s)", True, anIssue)
229 elif mtk.DFMMachining_SmallDepthBlindBoredHoleReliefIssue.CompareType(anIssue):
230 aManager.AddFeature("Small Depth Blind Bored Hole Relief Issue(s)", "Blind Bored Hole(s)", True, anIssue)
231 elif mtk.DFMMachining_DeepBoredHoleIssue.CompareType(anIssue):
232 aManager.AddFeature("Deep Bored Hole Issue(s)", "Bored Hole(s)", True, anIssue)
233 elif mtk.DFMMachining_SquareEndKeywayIssue.CompareType(anIssue):
234 aManager.AddFeature("Square End Keyway Issue(s)", "", False, anIssue)
235 elif mtk.DFMMachining_NonSymmetricalAxialSlotIssue.CompareType(anIssue):
236 aManager.AddFeature("Non Symmetrical Axial Slot Issue(s)", "", False, anIssue)
237
238 aManager.Print ("issues", PrintFeatureParameters)
239
240class PartProcessor(shape_processor.SolidProcessor):
241 def __init__(self, theOperation):
242 super().__init__()
243 self.myOperation = theOperation
244
245 def CombineFeatureLists(self, theFirst: mtk.MTKBase_FeatureList, theSecond: mtk.MTKBase_FeatureList):
246 for anElement in theSecond:
247 if (self.myOperation == mtk.Machining_OT_LatheMilling
248 and mtk.DFMMachining_MillingIssue.CompareType(anElement)
249 and not mtk.DFMMachining_DeepPocketIssue.CompareType(anElement)):
250 continue
251 theFirst.Append(anElement)
252
253 def ProcessSolid(self, theSolid: mtk.ModelData_Solid):
254 # Find features
255 aData = mtk.Machining_Data()
256 aRecognizer = mtk.Machining_FeatureRecognizer()
257 aRecognizer.Parameters().SetOperation(self.myOperation)
258 aRecognizer.Perform (theSolid, aData)
259
260 # Run drilling analyzer for found features
261 aDrillingParameters = mtk.DFMMachining_DrillingAnalyzerParameters()
262 aDrillingAnalyzer = mtk.DFMMachining_Analyzer(aDrillingParameters)
263 anIssueList = aDrillingAnalyzer.Perform(theSolid, aData)
264
265 # Run milling analyzer for found features
266 aMillingParameters = mtk.DFMMachining_MillingAnalyzerParameters()
267 aMillingAnalyzer = mtk.DFMMachining_Analyzer(aMillingParameters)
268 aMillingIssueList = aMillingAnalyzer.Perform(theSolid, aData)
269 # Combine issue lists
270 self.CombineFeatureLists(anIssueList, aMillingIssueList)
271
272 aTurningIssueList = mtk.MTKBase_FeatureList()
273 if self.myOperation == mtk.Machining_OT_LatheMilling:
274 # Run turning analyzer for found features
275 aTurninigParameters = mtk.DFMMachining_TurningAnalyzerParameters()
276 aTurningAnalyzer = mtk.DFMMachining_Analyzer(aTurninigParameters)
277 aTurningIssueList = aTurningAnalyzer.Perform(theSolid, aData)
278
279 # Combine issue lists
280 self.CombineFeatureLists(anIssueList, aTurningIssueList)
281
282 PrintIssues(anIssueList)
283
284def PrintSupportedOperations():
285 print("Supported operations:")
286 print(" milling:\t CNC Machining Milling feature recognition")
287 print(" turning:\t CNC Machining Lathe+Milling feature recognition")
288
289def OperationType(theOperationStr: str):
290 aProcessMap = {
291 "milling": mtk.Machining_OT_Milling,
292 "turning": mtk.Machining_OT_LatheMilling
293 }
294
295 if theOperationStr in aProcessMap:
296 return aProcessMap[theOperationStr]
297 else:
298 return mtk.Machining_OT_Undefined
299
300def main(theSource: str, theOperationStr: str):
301 aKey = license.Value()
302
303 if not mtk.LicenseManager.Activate(aKey):
304 print("Failed to activate Manufacturing Toolkit license.")
305 return 1
306
307 aModel = mtk.ModelData_Model()
308 aReader = mtk.ModelData_ModelReader()
309
310 # Reading the file
311 if not aReader.Read(mtk.UTF16String(theSource), aModel):
312 print("Failed to open and convert the file " + theSource)
313 return 1
314
315 print("Model: ", aModel.Name(), "\n", sep="")
316
317 anOperation = OperationType(theOperationStr)
318 if anOperation == mtk.Machining_OT_Undefined:
319 print("Unsupported operation - " , theOperationStr)
320 print("Please use one of the following.")
321 PrintSupportedOperations()
322 return 1
323
324 # Processing
325 aPartProcessor = PartProcessor(anOperation)
326 aVisitor = mtk.ModelData_ModelElementUniqueVisitor(aPartProcessor)
327 aModel.Accept(aVisitor)
328
329 return 0
330
331if __name__ == "__main__":
332 if len(sys.argv) != 3:
333 print("Usage: <input_file> <operation>, where:")
334 print(" <input_file> is a name of the file to be read")
335 print(" <operation> is a name of desired machining operation")
336 PrintSupportedOperations()
337 sys.exit()
338
339 aSource = os.path.abspath(sys.argv[1])
340 anOperation = sys.argv[2]
341
342 sys.exit(main(aSource, anOperation))