CNC DFM: undercut recognition in MTK

Learn why undercuts make it difficult to manufacture a part via CNC milling, and how to detect them with MTK

Roman Lygin
Roman Lygin November 13, 2025 ● 4 min read

We have just released a new DFM check - undercut recognition — in the MTK release 2025.7. This post provides more details on this new product feature.

Undercuts are regions a tool cannot reach from a chosen approach direction (e.g., Z+ on a 3-axis mill). Catching them early prevents impossible quotes, broken tools, and back-and-forth with customers. This post explains how MTK detects undercuts on solid B-Rep models, what you get in the API, and how to wire it into your DFM and pricing pipeline.

Problem (why this is hard)  

Most CAD files aren’t authored for manufacturability checks. Local blends hide access issues, trims are imperfect, and the same part can be machinable or not depending on fixture and approach. Manual visual checks don’t scale when you’re quoting batches.

Inputs and assumptions  

  • Geometry: solid B-Rep only (i.e. faces, edges, vertices). Mesh-based analysis is not included in this release.
  • Formats: B-Rep formats (STEP, Parasolid, Solidworks and other formats with B-Rep inside).

How it works (high-level)  

  1. Undercut recognition works on a set of recognized pockets. So pocket recognition (as part of a broader CNC feature recognition) is a prerequisite to the algorithm.
  2. Each pocket is processed independently and its axis is used to identfy those inaccessible regions that constiture the undercut.

Output (what you get back)  

Each detected undercut returns an associated pocket (that was initially recognized and was used a ‘context’ for undercut detection) and a list of B-Rep faces that form it. Those faces are a subset of pocket faces.

When using persistent representation (.mtkweb) faces are represented via a face ID’s list.

JSON (illustrative)


"dfm": {
    "name": "Design for Manufacturing",
    "totalFeatureCount" : "1",
    "featureGroups": [
        {
            "name": "Undercut Issue(s)",
            "color": "(200, 105, 49)",
            "totalGroupFeatureCount": "1",
            "features": [
                {
                    "shapeIDCount": "3",
                    "shapeIDs": [
                        { "id": "150" },
                        { "id": "144" },
                        { "id": "280" }
                    ]
                }
            ]
        }
    ]
}

Performance

Performance costs to detect undercuts are really Incremental. The major price is paid during the pocket recognition.

API Quickstart

Refer to a general DFM analyzer example in the documentation

C++ (illustrative)  


void ProcessSolid (const ModelData::Solid& theSolid) override
{
	// Find features
	Machining_Data aData;
	Machining_FeatureRecognizer aRecognizer;
	aRecognizer.Parameters().SetOperation (myOperation);
	aRecognizer.Perform (theSolid, aData);


	...


	// Run milling analyzer for found features
	DFMMachining_MillingAnalyzerParameters aMillingParameters;
	DFMMachining_Analyzer aMillingAnalyzer (aMillingParameters);
	MTKBase_FeatureList aMillingIssueList = aMillingAnalyzer.Perform (theSolid, aData);


	CombineFeatureLists (anIssueList, aMillingIssueList);
	...
}


void PrintIssues (const MTKBase_FeatureList& theIssueList)
{
    FeatureGroupManager aManager;
 
    //group by parameters to provide more compact information about issues
    for (size_t i = 0; i < theIssueList.Size(); ++i) {
        const auto& anIssue = theIssueList[i];
 
	 if (anIssue.IsOfType<DFMMachining_SmallDiameterHoleIssue>()) {
...
        } else if (anIssue.IsOfType<DFMMachining_UndercutIssue>()) {
            aManager.AddFeature ("Undercut Issue(s)", "", false, anIssue);
        }
...
	}

... 
}

Python (illustrative)  


def ProcessSolid(self, theSolid: mtk.ModelData_Solid):
	# Find features
	aData = mtk.Machining_Data()
	aRecognizer = mtk.Machining_FeatureRecognizer()
	aRecognizer.Parameters().SetOperation(self.myOperation)
	aRecognizer.Perform (theSolid, aData)

	# Run milling analyzer for found features
	aMillingParameters = mtk.DFMMachining_MillingAnalyzerParameters()
	aMillingAnalyzer = mtk.DFMMachining_Analyzer(aMillingParameters)
	aMillingIssueList = aMillingAnalyzer.Perform(theSolid, aData)
	# Combine issue lists
	self.CombineFeatureLists(anIssueList, aMillingIssueList)
...
	PrintIssues(anIssueList)


def PrintIssues(theIssueList: mtk.MTKBase_FeatureList):
    aManager = feature_group.FeatureGroupManager()
 
    #group by parameters to provide more compact information about features
    for anIssue in theIssueList:
        
        if mtk.DFMMachining_SmallDiameterHoleIssue.CompareType(anIssue):
            aManager.AddFeature("Small Diameter Hole Issue(s)", "Hole(s)", True, anIssue)
        elif mtk.DFMMachining_UndercutIssue.CompareType(anIssue):
            aManager.AddFeature("Undercut Issue(s)", "", False, anIssue)
... 
    aManager.Print ("issues", PrintFeatureParameters)

How detecting undercuts helps you  

  • Faster “no-go” decisions for CNC milling.
  • Fewer surprises after CAM starts.
  • Clear, visual explanations for customers on why reorientation or redesign is needed.

Limitations

  • Solid B-Rep only; no mesh analysis.
  • Undercuts are detected in the context of pockets. So complex pockets may fail to be recognized (where the pocket itself is ambigous or consists of multiple ‘islands’)

Conclusion

Undercuts are a classic “looks fine in CAD, fails in the shop” problem. MTK’s undercut recognition turns that into a clear, early signal — directly on your solid B-Rep — so quotes and DFM reviews stay grounded in manufacturable reality.

Next steps

Check out documentation. Submit evaluation requst. Or just drop me a direct email. We’ll be happy to discuss your project to see how MTK could help you.

Join the CADEXSOFT newsletter

Stay updated with our latest news and product releases!

Bring CAD intelligence

to your quoting or MaaS platform

Contact sales