Hide menu
Loading...
Searching...
No Matches
CNC Machining DFM Analyzer Example

Demonstrates how to perform machining design analysis on a 3D model and print information about found issues and their parameters in a console.

Overview

In this example demonstrates how to perform machining design analysis on a 3D model using machining dfm analyzer tool (DFMMachining_Analyzer). For this purpose, used a console application that imports a STEP model, traverses through unique ModelData::Part , creates and runs DFMMachining_Analyzer, groups and prints information about found issues and their parameters into console. Machining design analysis will be performed for each unique ModelData::Part , but only for the scope of accepted geometries.


Application needs 2 input arguments to run:

Usage: machining_dfm_analyzer <input_file> <operation>, where:
<input_file> is a name of the file to be read
<operation> is a name of desired machining operation
Supported operations:
milling: CNC Machining Milling feature recognition
turning: CNC Machining Lathe+Milling feature recognition


For more information about machining design analysis visit Design for Manufacturing (DFM) page.

Implementation

PartProcessor class is inherited from SolidProcessor and overrides ProcessSolid method that are used to run design analysis on given shape.
To reduce computation time, Machining_Data will be used as an input argument to perform design analysis. Machining data contains information about found features, therefore, the first step is to run Machining_FeatureRecognizer. The Machining_FeatureRecognizerParameters.SetOperation() method of the tool parameters is used to set the type of operation (Milling or LatheMilling). The operation type will be taking into account during recognition process and the recognition result will be different depending on it.
Once feature recognition is done, design analysis is run for various sub-processes (drilling / milling / turning). CombineFeatureLists method is used to combine issues from design analysis of different sub-processes.
After design analysis is performed, PrintIssues method is used to print information about found features and their parameters in a console.
Visit Model Explore Helper Implementation page for more information about base SolidProcessor class implementation.

class PartProcessor : public SolidProcessor
{
public:
PartProcessor (Machining_OperationType theOperation) : myOperation (theOperation)
{}
void ProcessSolid (const ModelData::Solid& theSolid) override
{
// Find features
Machining_Data aData;
Machining_FeatureRecognizer aRecognizer;
aRecognizer.Parameters().SetOperation (myOperation);
aRecognizer.Perform (theSolid, aData);
// Run drilling analyzer for found features
DFMMachining_DrillingAnalyzerParameters aDrillingParameters;
DFMMachining_Analyzer aDrillingAnalyzer (aDrillingParameters);
auto anIssueList = aDrillingAnalyzer.Perform (theSolid, aData);
// Run milling analyzer for found features
DFMMachining_MillingAnalyzerParameters aMillingParameters;
DFMMachining_Analyzer aMillingAnalyzer (aMillingParameters);
MTKBase_FeatureList aMillingIssueList = aMillingAnalyzer.Perform (theSolid, aData);
// Combine issue lists
CombineFeatureLists (anIssueList, aMillingIssueList);
MTKBase_FeatureList aTurningIssueList;
if (myOperation == Machining_OT_LatheMilling) {
// Run turning analyzer for found features
DFMMachining_TurningAnalyzerParameters aTurninigParameters;
DFMMachining_Analyzer aTurningAnalyzer (aTurninigParameters);
aTurningIssueList = aTurningAnalyzer.Perform (theSolid, aData);
// Combine issue lists
CombineFeatureLists (anIssueList, aTurningIssueList);
}
PrintIssues (anIssueList);
}
private:
void CombineFeatureLists (MTKBase_FeatureList& theFirst, const MTKBase_FeatureList& theSecond)
{
for (size_t i = 0; i < theSecond.Size(); i++) {
const auto& aFeature = theSecond[i];
if (myOperation == Machining_OT_LatheMilling
&& aFeature.IsOfType<DFMMachining_MillingIssue>()
&& !aFeature.IsOfType<DFMMachining_DeepPocketIssue>()) {
continue;
}
theFirst.Append (aFeature);
}
}
};
Machining_OperationType
Defines an operation type in machining.
Definition Machining_OperationType.hxx:28
@ Machining_OT_Undefined
Unknown operation type.
Definition Machining_OperationType.hxx:31

To traverse only unique parts of the imported model, the ModelData::ModelElementUniqueVisitor class is used.

PartProcessor aPartProcessor;
ModelData::ModelElementUniqueVisitor aVisitor (aPartProcessor);
aModel.Accept (aVisitor);

After performing design analysis, the object of FeatureGroupManager class is used to group and sort found issues. For this purpose, there is a traverse through all found issues and add each of them to FeatureGroupManager with a specified name.

for (size_t i = 0; i < theIssueList.Size(); ++i) {
const auto& anIssue = theIssueList[i];
//drilling
if (anIssue.IsOfType<DFMMachining_SmallDiameterHoleIssue>()) {
aManager.AddFeature ("Small Diameter Hole Issue(s)", "Hole(s)", true, anIssue);
} else if (anIssue.IsOfType<DFMMachining_DeepHoleIssue>()) {
aManager.AddFeature ("Deep Hole Issue(s)", "Hole(s)", true, anIssue);
} else if (anIssue.IsOfType<DFMMachining_NonStandardDiameterHoleIssue>()) {
aManager.AddFeature ("Non Standard Diameter Hole Issue(s)", "Hole(s)", true, anIssue);
} else if (anIssue.IsOfType<DFMMachining_NonStandardDrillPointAngleBlindHoleIssue>()) {
aManager.AddFeature ("Non Standard Drill Point Angle Blind Hole Issue(s)", "Hole(s)", true, anIssue);
} else if (anIssue.IsOfType<DFMMachining_FlatBottomHoleIssue>()) {
aManager.AddFeature ("Flat Bottom Hole Issue(s)", "", false, anIssue);
} else if (anIssue.IsOfType<DFMMachining_NonPerpendicularHoleIssue>()) {
aManager.AddFeature ("Non Perpendicular Hole Issue(s)", "", false, anIssue);
} else if (anIssue.IsOfType<DFMMachining_IntersectingCavityHoleIssue>()) {
aManager.AddFeature ("Intersecting Cavity Hole Issue(s)", "", false, anIssue);
} else if (anIssue.IsOfType<DFMMachining_PartialHoleIssue>()) {
aManager.AddFeature ("Partial Hole Issue(s)", "Hole(s)", true, anIssue);
}
//milling
else if (anIssue.IsOfType<DFMMachining_NonStandardRadiusMilledPartFloorFilletIssue>()) {
aManager.AddFeature ("Non Standard Radius Milled Part Floor Fillet Issue(s)", "Floor Fillet(s)", true, anIssue);
} else if (anIssue.IsOfType<DFMMachining_DeepPocketIssue>()) {
aManager.AddFeature ("Deep Pocket Issue(s)", "Pocket(s)", true, anIssue);
} else if (anIssue.IsOfType<DFMMachining_HighBossIssue>()) {
aManager.AddFeature ("High Boss Issue(s)", "Boss(es)", true, anIssue);
} else if (anIssue.IsOfType<DFMMachining_LargeMilledPartIssue>()) {
aManager.AddFeature ("Large Milled Part Issue(s)", "Part(s)", true, anIssue);
} else if (anIssue.IsOfType<DFMMachining_SmallRadiusMilledPartInternalCornerIssue>()) {
aManager.AddFeature ("Small Radius Milled Part Internal Corner Issue(s)", "Internal Corner(s)", true, anIssue);
} else if (anIssue.IsOfType<DFMMachining_NonPerpendicularMilledPartShapeIssue>()) {
aManager.AddFeature ("Non Perpendicular Milled Part Shape Issue(s)", "Shape(s)", true, anIssue);
} else if (anIssue.IsOfType<DFMMachining_MilledPartExternalEdgeFilletIssue>()) {
aManager.AddFeature ("Milled Part External Edge Fillet Issue(s)", "", false, anIssue);
} else if (anIssue.IsOfType<DFMMachining_InconsistentRadiusMilledPartFloorFilletIssue>()) {
aManager.AddFeature ("Inconsistent Radius Milled Part Floor Fillet Issue(s)", "Floor Fillet(s)", true, anIssue);
} else if (anIssue.IsOfType<DFMMachining_NarrowRegionInPocketIssue>()) {
aManager.AddFeature ("Narrow Region In Pocket Issue(s)", "Region(s)", true, anIssue);
} else if (anIssue.IsOfType<DFMMachining_LargeDifferenceRegionsSizeInPocketIssue>()) {
aManager.AddFeature ("Large Difference Regions Size In Pocket Issue(s)", "Region Size(s)", true, anIssue);
} else if (anIssue.IsOfType<DFMMachining_SmallWallThicknessIssue>()) {
aManager.AddFeature ("Small Wall Thickness Issue(s)", "Wall(s)", true, anIssue);
}
//turning
else if (anIssue.IsOfType<DFMMachining_IrregularTurnedPartOuterDiameterProfileReliefIssue>()) {
aManager.AddFeature ("Irregular Turned Part Outer Diameter Profile Relief Issue(s)", "Outer Diameter Profile Relief(s)", true, anIssue);
} else if (anIssue.IsOfType<DFMMachining_SmallRadiusTurnedPartInternalCornerIssue>()) {
aManager.AddFeature ("Small Radius Turned Part Internal Corner Issue(s)", "Internal Corner(s)", true, anIssue);
} else if (anIssue.IsOfType<DFMMachining_LargeTurnedPartIssue>()) {
aManager.AddFeature ("Large Turned Part Issue(s)", "Part(s)", true, anIssue);
} else if (anIssue.IsOfType<DFMMachining_LongSlenderTurnedPartIssue>()) {
aManager.AddFeature ("Long Slender Turned Part Issue(s)", "Part(s)", true, anIssue);
} else if (anIssue.IsOfType<DFMMachining_SmallDepthBlindBoredHoleReliefIssue>()) {
aManager.AddFeature ("Small Depth Blind Bored Hole Relief Issue(s)", "Blind Bored Hole(s)", true, anIssue);
} else if (anIssue.IsOfType<DFMMachining_DeepBoredHoleIssue>()) {
aManager.AddFeature ("Deep Bored Hole Issue(s)", "Bored Hole(s)", true, anIssue);
} else if (anIssue.IsOfType<DFMMachining_SquareEndKeywayIssue>()) {
aManager.AddFeature ("Square End Keyway Issue(s)", "", false, anIssue);
} else if (anIssue.IsOfType<DFMMachining_NonSymmetricalAxialSlotIssue>()) {
aManager.AddFeature ("Non Symmetrical Axial Slot Issue(s)", "", false, anIssue);
}
}

After adding all found issues to FeatureGroupManager, a Print method of the manager is used to print information about found issues and their parameters in a console. PrintFeatureParameters is created to explore and print issue parameters. It uses as an input parameter of Print method.

auto PrintFeatureParameters = [] (const MTKBase_Feature& theIssue)
{
//drilling
if (theIssue.IsOfType<DFMMachining_SmallDiameterHoleIssue>()) {
const auto& aSDHIssue = static_cast<const DFMMachining_SmallDiameterHoleIssue&> (theIssue);
FeatureGroupManager::PrintFeatureParameter ("expected min diameter", aSDHIssue.ExpectedMinDiameter(), "mm");
FeatureGroupManager::PrintFeatureParameter ("actual diameter", aSDHIssue.ActualDiameter(), "mm");
} else if (theIssue.IsOfType<DFMMachining_DeepHoleIssue>()) {
const auto& aDHIssue = static_cast<const DFMMachining_DeepHoleIssue&> (theIssue);
FeatureGroupManager::PrintFeatureParameter ("expected max depth", aDHIssue.ExpectedMaxDepth(), "mm");
FeatureGroupManager::PrintFeatureParameter ("actual depth", aDHIssue.ActualDepth(), "mm");
} else if (theIssue.IsOfType<DFMMachining_NonStandardDiameterHoleIssue>()) {
const auto& aNSDHIssue = static_cast<const DFMMachining_NonStandardDiameterHoleIssue&> (theIssue);
FeatureGroupManager::PrintFeatureParameter (
"nearest standard diameter", aNSDHIssue.NearestStandardDiameter(), "mm");
FeatureGroupManager::PrintFeatureParameter (
"actual diameter", aNSDHIssue.ActualDiameter(), "mm");
} else if (theIssue.IsOfType<DFMMachining_NonStandardDrillPointAngleBlindHoleIssue>()) {
const auto& aNSDPABHIssue = static_cast<const DFMMachining_NonStandardDrillPointAngleBlindHoleIssue&> (theIssue);
FeatureGroupManager::PrintFeatureParameter (
"nearest standard angle", ToDegrees (aNSDPABHIssue.NearestStandardAngle()), "deg");
FeatureGroupManager::PrintFeatureParameter (
"actual angle", ToDegrees (aNSDPABHIssue.ActualAngle()), "deg");
}
else if (theIssue.IsOfType<DFMMachining_FlatBottomHoleIssue>()) {
//no parameters
} else if (theIssue.IsOfType<DFMMachining_NonPerpendicularHoleIssue>()) {
//no parameters
} else if (theIssue.IsOfType<DFMMachining_IntersectingCavityHoleIssue>()) {
//no parameters
} else if (theIssue.IsOfType<DFMMachining_PartialHoleIssue>()) {
const auto& aPHIssue = static_cast<const DFMMachining_PartialHoleIssue&> (theIssue);
FeatureGroupManager::PrintFeatureParameter (
"expected min material percent", aPHIssue.ExpectedMinMaterialPercent(), "");
FeatureGroupManager::PrintFeatureParameter (
"actual material percent", aPHIssue.ActualMaterialPercent(), "");
}
//milling
else if (theIssue.IsOfType<DFMMachining_NonStandardRadiusMilledPartFloorFilletIssue>()) {
const auto& aNSRMPFFIssue =
static_cast<const DFMMachining_NonStandardRadiusMilledPartFloorFilletIssue&> (theIssue);
FeatureGroupManager::PrintFeatureParameter (
"nearest standard radius", aNSRMPFFIssue.NearestStandardRadius(), "mm");
FeatureGroupManager::PrintFeatureParameter (
"actual radius", aNSRMPFFIssue.ActualRadius(), "mm");
} else if (theIssue.IsOfType<DFMMachining_DeepPocketIssue>()) {
const auto& aDPIssue = static_cast<const DFMMachining_DeepPocketIssue&> (theIssue);
FeatureGroupManager::PrintFeatureParameter ("expected max depth", aDPIssue.ExpectedMaxDepth(), "mm");
FeatureGroupManager::PrintFeatureParameter ("actual depth", aDPIssue.ActualDepth(), "mm");
} else if (theIssue.IsOfType<DFMMachining_HighBossIssue>()) {
const auto& aHBIssue = static_cast<const DFMMachining_HighBossIssue&> (theIssue);
FeatureGroupManager::PrintFeatureParameter ("expected max height", aHBIssue.ExpectedMaxHeight(), "mm");
FeatureGroupManager::PrintFeatureParameter ("actual height", aHBIssue.ActualHeight(), "mm");
} else if (theIssue.IsOfType<DFMMachining_LargeMilledPartIssue>()) {
const auto& aLMPIssue = static_cast<const DFMMachining_LargeMilledPartIssue&> (theIssue);
const auto& anExpectedSize = aLMPIssue.ExpectedMaxMilledPartSize();
const auto& anActualSize = aLMPIssue.ActualMilledPartSize();
FeatureGroupManager::PrintFeatureParameter (
"expected max size (LxWxH)",
ArrayType ({ anExpectedSize.Length(), anExpectedSize.Width(), anExpectedSize.Height() }),
"mm");
FeatureGroupManager::PrintFeatureParameter (
"actual size (LxWxH)",
ArrayType ({ anActualSize.Length(), anActualSize.Width(), anActualSize.Height() }),
"mm");
} else if (theIssue.IsOfType<DFMMachining_SmallRadiusMilledPartInternalCornerIssue>()) {
const auto& aSRMPICIssue =
static_cast<const DFMMachining_SmallRadiusMilledPartInternalCornerIssue&> (theIssue);
FeatureGroupManager::PrintFeatureParameter ("expected min radius", aSRMPICIssue.ExpectedMinRadius(), "mm");
FeatureGroupManager::PrintFeatureParameter ("actual radius", aSRMPICIssue.ActualRadius(), "mm");
} else if (theIssue.IsOfType<DFMMachining_NonPerpendicularMilledPartShapeIssue>()) {
const auto& aNPMPSIssue =
static_cast<const DFMMachining_NonPerpendicularMilledPartShapeIssue&> (theIssue);
FeatureGroupManager::PrintFeatureParameter ("actual angle", ToDegrees (aNPMPSIssue.ActualAngle()), "deg");
} else if (theIssue.IsOfType<DFMMachining_MilledPartExternalEdgeFilletIssue>()) {
//no parameters
} else if (theIssue.IsOfType<DFMMachining_InconsistentRadiusMilledPartFloorFilletIssue>()) {
const auto& aIRMPFFIssue =
static_cast<const DFMMachining_InconsistentRadiusMilledPartFloorFilletIssue&> (theIssue);
FeatureGroupManager::PrintFeatureParameter ("expected radius", aIRMPFFIssue.ExpectedRadius(), "mm");
FeatureGroupManager::PrintFeatureParameter ("actual radius", aIRMPFFIssue.ActualRadius(), "mm");
} else if (theIssue.IsOfType<DFMMachining_NarrowRegionInPocketIssue>()) {
const auto& aSMNRDIssue =
static_cast<const DFMMachining_NarrowRegionInPocketIssue&> (theIssue);
FeatureGroupManager::PrintFeatureParameter ("expected minimum region size", aSMNRDIssue.ExpectedMinRegionSize(), "mm");
FeatureGroupManager::PrintFeatureParameter ("actual region size", aSMNRDIssue.ActualRegionSize(), "mm");
} else if (theIssue.IsOfType<DFMMachining_LargeDifferenceRegionsSizeInPocketIssue>()) {
const auto& aLMNRRIssue =
static_cast<const DFMMachining_LargeDifferenceRegionsSizeInPocketIssue&> (theIssue);
FeatureGroupManager::PrintFeatureParameter ("expected regions maximum to minimum size ratio", aLMNRRIssue.ExpectedMaxRegionsMaxToMinSizeRatio(), "");
FeatureGroupManager::PrintFeatureParameter ("actual regions maximum to minimum size ratio", aLMNRRIssue.ActualMaxRegionsMaxToMinSizeRatio(), "");
} else if (theIssue.IsOfType<DFMMachining_SmallWallThicknessIssue>()) {
const auto& aSWTIssue = static_cast<const DFMMachining_SmallWallThicknessIssue&> (theIssue);
FeatureGroupManager::PrintFeatureParameter ("expected min wall thickness", aSWTIssue.ExpectedMinThickness(), "mm");
FeatureGroupManager::PrintFeatureParameter ("actual wall thickness", aSWTIssue.ActualThickness(), "mm");
}
//turning
else if (theIssue.IsOfType<DFMMachining_IrregularTurnedPartOuterDiameterProfileReliefIssue>()) {
const auto& anITPODPRIssue =
static_cast<const DFMMachining_IrregularTurnedPartOuterDiameterProfileReliefIssue&> (theIssue);
FeatureGroupManager::PrintFeatureParameter (
"expected max incline angle", ToDegrees (anITPODPRIssue.ExpectedMaxFaceInclineAngle()), "deg");
FeatureGroupManager::PrintFeatureParameter (
"actual incline angle", ToDegrees (anITPODPRIssue.ActualFaceInclineAngle()), "deg");
} else if (theIssue.IsOfType<DFMMachining_SmallRadiusTurnedPartInternalCornerIssue>()) {
const auto& aSRTPICIssue =
static_cast<const DFMMachining_SmallRadiusTurnedPartInternalCornerIssue&> (theIssue);
FeatureGroupManager::PrintFeatureParameter ("expected min radius", aSRTPICIssue.ExpectedMinRadius(), "mm");
FeatureGroupManager::PrintFeatureParameter ("actual radius", aSRTPICIssue.ActualRadius(), "mm");
} else if (theIssue.IsOfType<DFMMachining_LargeTurnedPartIssue>()) {
const auto& aLTPIssue = static_cast<const DFMMachining_LargeTurnedPartIssue&> (theIssue);
const auto& anExpectedSize = aLTPIssue.ExpectedMaxTurnedPartSize();
const auto& anActualSize = aLTPIssue.ActualTurnedPartSize();
FeatureGroupManager::PrintFeatureParameter (
"expected max size (LxR)",
std::make_pair (anExpectedSize.Length(), anExpectedSize.Radius()),
"mm");
FeatureGroupManager::PrintFeatureParameter (
"actual size (LxR)",
std::make_pair (anActualSize.Length(), anActualSize.Radius()),
"mm");
} else if (theIssue.IsOfType<DFMMachining_LongSlenderTurnedPartIssue>()) {
const auto& aLSTPIssue =
static_cast<const DFMMachining_LongSlenderTurnedPartIssue&> (theIssue);
FeatureGroupManager::PrintFeatureParameter ("expected min length", aLSTPIssue.ExpectedMaxLength(), "mm");
FeatureGroupManager::PrintFeatureParameter ("actual length", aLSTPIssue.ActualLength(), "mm");
FeatureGroupManager::PrintFeatureParameter ("actual min diameter", aLSTPIssue.ActualMinDiameter(), "mm");
} else if (theIssue.IsOfType<DFMMachining_SmallDepthBlindBoredHoleReliefIssue>()) {
const auto& aSDBBHRIssue =
static_cast<const DFMMachining_SmallDepthBlindBoredHoleReliefIssue&> (theIssue);
FeatureGroupManager::PrintFeatureParameter (
"expected min relief depth", aSDBBHRIssue.ExpectedMinReliefDepth(), "mm");
FeatureGroupManager::PrintFeatureParameter (
"actual relief depth", aSDBBHRIssue.ActualReliefDepth(), "mm");
FeatureGroupManager::PrintFeatureParameter (
"actual diameter", aSDBBHRIssue.ActualDiameter(), "mm");
} else if (theIssue.IsOfType<DFMMachining_DeepBoredHoleIssue>()) {
const auto& aDBHIssue =
static_cast<const DFMMachining_DeepBoredHoleIssue&> (theIssue);
FeatureGroupManager::PrintFeatureParameter ("expected max depth", aDBHIssue.ExpectedMaxDepth(), "mm");
FeatureGroupManager::PrintFeatureParameter ("actual depth", aDBHIssue.ActualDepth(), "mm");
FeatureGroupManager::PrintFeatureParameter ("actual diameter", aDBHIssue.ActualDiameter(), "mm");
} else if (theIssue.IsOfType<DFMMachining_SquareEndKeywayIssue>()) {
//no parameters
} else if (theIssue.IsOfType<DFMMachining_NonSymmetricalAxialSlotIssue>()) {
//no parameters
}
};
aManager.Print ("issues", PrintFeatureParameters);

Visit Feature Group Helper Implementation page for more information about FeatureGroupManager class implementation.

Example output

Below is the example output for model from ./examples/models/Fresamento_CAM1_v3.stp and operation set to Milling.

The model Example output
Model: Fresamento_CAM1_v3.stp

Part #0 ["Fresamento_CAM1"] - solid #0 has:
    Deep Hole Issue(s): 4
        4 Hole(s) with
          expected max depth: 29.841 mm
          actual depth: 31.3245 mm
    Non Standard Diameter Hole Issue(s): 4
        4 Hole(s) with
          nearest standard diameter: 9 mm
          actual diameter: 8.526 mm
    Small Radius Milled Part Internal Corner Issue(s): 15
        1 Internal Corner(s) with
          expected min radius: 7.83333 mm
          actual radius: 7.5 mm
        1 Internal Corner(s) with
          expected min radius: 13.3361 mm
          actual radius: 5 mm
        1 Internal Corner(s) with
          expected min radius: 13.345 mm
          actual radius: 5 mm
        1 Internal Corner(s) with
          expected min radius: 13.3499 mm
          actual radius: 5 mm
        1 Internal Corner(s) with
          expected min radius: 13.35 mm
          actual radius: 5 mm
        1 Internal Corner(s) with
          expected min radius: 13.3547 mm
          actual radius: 5 mm
        2 Internal Corner(s) with
          expected min radius: 13.355 mm
          actual radius: 5 mm
        1 Internal Corner(s) with
          expected min radius: 13.3561 mm
          actual radius: 5 mm
        2 Internal Corner(s) with
          expected min radius: 13.3566 mm
          actual radius: 5 mm
        1 Internal Corner(s) with
          expected min radius: 13.3599 mm
          actual radius: 5 mm
        1 Internal Corner(s) with
          expected min radius: 13.3601 mm
          actual radius: 5 mm
        1 Internal Corner(s) with
          expected min radius: 13.3611 mm
          actual radius: 5 mm
        1 Internal Corner(s) with
          expected min radius: 13.3621 mm
          actual radius: 5 mm
    Narrow Region In Pocket Issue(s): 1
        1 Region(s) with
          expected minimum region size: 16 mm
          actual region size: 13.1867 mm

    Total issues: 24

Another example below is an output for model from ./examples/models/senthi.step and operation set to Lathe+Milling.

The model Example output
Model: senthi

Part #0 ["drawing no 1"] - solid #0 has:
    Small Radius Turned Part Internal Corner Issue(s): 2
        2 Internal Corner(s) with
          expected min radius: 5 mm
          actual radius: 0 mm

    Total issues: 2

Files