Demonstrates how to generate view and manufacturing information files for the imported model, that can be easily acessed through web interface for downstream analysis.
Overview
The example demonstrates how to create a console application to convert your model (the list of supported formats can be found here ) to compressed *.cdxweb format, generate thumbnail screenshot and useful manufacturing information about it with chosen data processor into *.json file). The model will be imported by ModelData_ModelReader. Then the choosen by input parameter certain part processor class will analyze a model. The list of possible analysis can be found in table below.
Finally, the converted *.cdxweb model will be saved to ${export_dir}/model.cdxweb
, a thumbnail to ${export_dir}/thumbnail.png
and all computed process data to ${export_dir}/process_data.json
Running the example
Application needs 6 following input arguments to run:
Usage: MTKConverter -i <import_file> -p <process> -e <export_folder> where:
<import_file> - filename of a model, that will be imported
<process> - what analysis should be performed on model
<export_folder> - export folder name where an output will be saved
Possible process parameter values
Parameter value | Process | Description |
machining_milling | CNC Machining | Milling feature recognition and dfm analysis |
machining_turning | Lathe+Milling feature recognition and dfm analysis |
sheet_metal | Sheet Metal | Feature recognition, unfolding and dfm analysis |
wall_thickness | Wall Thickness | Wall Thickness analysis |
Example:
MTKConverter -i C:\\models\\test.step -p machining_milling -e C:\\models\\test
Implementation
The ModelData_ModelReader was used to import the model. To see more information about the model import visit the following example.
MTKConverter_ReturnCode Import (const Base_UTF16String& theFilePath, ModelData_Model& theModel)
{
std::cout << "Importing " << theFilePath << "..." << std::flush;
ModelData_ModelReader aReader;
if (!aReader.Read (theFilePath, theModel)) {
std::cerr << std::endl << "ERROR: Failed to import " << theFilePath << ". Exiting" << std::endl;
return MTKConverter_RC_ImportError;
}
return MTKConverter_RC_OK;
}
Then Process
method was created for a model analysis with chosen by <process> value processor. The ModelData_Model.AssignUuids() method is used to assign persistent id's to unique parts of the model. These id's will be used to connect parts with process data saved in json file. The processor is a MTKConverter_PartProcessor
class, that can analyse all parts of the imported model. The ProcessType
method can parse a <process> parameter value to choose MTKConverter_PartProcessor
class, which will run relative analyzer tools. The ModelData_SceneGraphElementUniqueVisitor is used to traverse and retrieve only unique parts of the imported model.
MTKConverter_ReturnCode Process (const Base_UTF16String& theProcess, ModelData_Model& theModel,
MTKConverter_Report& theReport, ModelData_Model& theProcessModel)
{
std::cout << "Processing " << theProcess << "..." << std::flush;
theModel.AssignUuids();
auto ApplyProcessorToModel = [&theModel, &theReport] (MTKConverter_PartProcessor& theProcessor) {
ModelData_SceneGraphElementUniqueVisitor aVisitor (theProcessor);
theModel.Accept (aVisitor);
for (const auto& i : theProcessor.myData) {
theReport.AddData (i);
}
};
auto aProcessType = ProcessType (theProcess);
switch (aProcessType) {
case MTKConverter_PT_WallThickness:
{
MTKConverter_WallThicknessProcessor aProcessor (800);
ApplyProcessorToModel (aProcessor);
break;
}
case MTKConverter_PT_MachiningMilling:
{
ApplyProcessorToModel (aProcessor);
break;
}
case MTKConverter_PT_MachiningTurning:
{
ApplyProcessorToModel (aProcessor);
break;
}
case MTKConverter_PT_SheetMetal:
{
theProcessModel.SetName (theModel.Name() + "_unfolded");
MTKConverter_SheetMetalProcessor aProcessor (theProcessModel);
ApplyProcessorToModel (aProcessor);
break;
}
case MTKConverter_PT_Undefined:
default : return MTKConverter_RC_InvalidArgument;
}
return MTKConverter_RC_OK;
}
@ Machining_OT_LatheMilling
Lathe + Milling operation type.
Definition: Machining_OperationType.hxx:31
@ Machining_OT_Milling
Milling operation type.
Definition: Machining_OperationType.hxx:30
Before we dive into how the model is processed with MTKConverter_PartProcessor
class after the ApplyProcessorToModel was ran the inheritance hierarchy should be observed.
-
Firstly, the MTKConverter_PartProcessor
class, inherited from the VoidElementVisitor, was created where the processing method void operator() (const ModelData_Part& thePart)
was overrided to explore the model and collect each ModelData_Part. Then, for BRep representation ModelData_Solid and ModelData_Shell will be extracted by ModelData_Shape::Iterator. The ProcessSolid
, ProcessShell
and ProcessMesh
is developed to analyze the certain shapes of ModelData_Part. Some analysis requires postprocessing with PostPartProcess
method. These 4 last methods will be described further.
void MTKConverter_PartProcessor::operator() (const ModelData_Part& thePart)
{
if (auto aBRep = thePart.BRepRepresentation()) {
const auto& aBodyList = aBRep.Get();
for (size_t i = 0, n = aBodyList.Size(); i < n; ++i) {
const auto& aBody = aBodyList[i];
ModelData_Shape::Iterator aShapeIt (aBody);
while (aShapeIt.HasNext()) {
const auto& aShape = aShapeIt.Next();
if (aShape.Type() == ModelData_ST_Solid) {
ProcessSolid (thePart, ModelData_Solid::Cast (aShape));
} else if (aShape.Type() == ModelData_ST_Shell) {
ProcessShell (thePart, ModelData_Shell::Cast (aShape));
}
}
}
} else if (auto aPolyRep = thePart.PolyRepresentation (ModelData_RM_Poly)) {
const auto& aPolyList = aPolyRep.Get();
for (size_t i = 0; i < aPolyList.Size(); ++i) {
const auto& aPVS = aPolyList[i];
if (aPVS.IsOfType<ModelData_IndexedTriangleSet>()) {
ProcessMesh (thePart, static_cast<const ModelData_IndexedTriangleSet&> (aPVS));
}
}
}
PostPartProcess (thePart);
}
MTKConverter_VoidPartProcessor
was inherited from MTKConverter_PartProcessor
at first with empty defined methods for processing, because not all processor can analyse Shell, Mesh and requires postprocessing. Then for each <process> different class, inherited from MTKConverter_VoidPartProcessor
, was developed. The table below demonstrates what classes were created for each process and which methods were overriden.
Processor classes
Process | Class | ProcessSolid | ProcessShell | ProcessMesh | PostPartProcess |
CNC Machining | MTKConverter_MachiningProcessor | + | - | - | - |
Sheet Metal | MTKConverter_SheetMetalProcessor | + | - | + |
Wall Thickness | MTKConverter_WallThicknessProcessor | - | + | - |
-
Let's take the MTKConverter_SheetMetalProcessor
as example, because it supports almost all methods of MTKConverter_PartProcessor
. It uses SheetMetal_Analyzer for shape processing. In constructor both supported tools (SheetMetal_FeatureRecognizer, SheetMetal_Unfolder) were added to SheetMetal_Analyzer. Analyzer classes can be used to run all tools together, however it should be mentioned, that such tools allow separated calls. The example of such separate call for SheetMetal_Unfolder can be found here.
MTKConverter_SheetMetalProcessor::MTKConverter_SheetMetalProcessor (
cadex::ModelData_Model& theUnfoldedModel) :
myUnfoldedModel (theUnfoldedModel)
{
myAnalyzer.AddTool (SheetMetal_FeatureRecognizer());
myAnalyzer.AddTool (SheetMetal_Unfolder());
}
Provides CAD Exchanger data model.
Definition: ModelData_Model.hxx:43
The Perfom
method of SheetMetal_Analyzer will be called to run analysis with added tools for Solid and Shell respectively. The ProcessMesh
method looks the same as these two, however, only supported by MTKConverter_WallThicknessProcessor
.
void MTKConverter_SheetMetalProcessor::ProcessSolid (
{
auto anSMData = myAnalyzer.Perform (theSolid, CalculateInitialThicknessValue (theSolid));
UpdateProcessData (anSMData, thePart);
}
void MTKConverter_SheetMetalProcessor::ProcessShell (
{
auto anSMData = myAnalyzer.Perform (theShell);
UpdateProcessData (anSMData, thePart);
}
Defines a leaf node in the scene graph hiearchy.
Definition: ModelData_Part.hxx:35
Defines a connected set of faces.
Definition: ModelData_Shell.hxx:31
Defines a topological solid.
Definition: ModelData_Solid.hxx:31
After the analysis was done the PostPartProcess
method will be run. MTKConverter_SheetMetalProcessor
is using such method to compute polygonal representation via ModelAlgo_BRepMesher for unfolded part.
void MTKConverter_SheetMetalProcessor::PostPartProcess (const ModelData_Part& thePart)
{
if (!myCurrentUnfoldedBRep) {
return;
}
ModelData_Part anUnfoldedPart (thePart.Name());
anUnfoldedPart.SetUuid (thePart.Uuid());
anUnfoldedPart.AddRepresentation (myCurrentUnfoldedBRep);
ModelAlgo_BRepMesher aMesher;
aMesher.Compute (anUnfoldedPart);
myUnfoldedModel.AddRoot (anUnfoldedPart);
myCurrentUnfoldedBRep = ModelData_BRepRepresentation();
}
Finally, after the processing, the model will be converted to *.cdxweb format and thumbnail generated.
MTKConverter_ReturnCode Export (const Base_UTF16String& theFolderPath,
const ModelData_WriterParameters& theWriterParams,
const ModelData_Model& theModel,
const MTKConverter_Report& theReport,
const ModelData_Model& theProcessModel)
{
std::cout << "Exporting " << theFolderPath << "..." << std::flush;
Base_UTF16String aModelPath = theFolderPath + "/" + theModel.Name() + ".cdxweb" + "/scenegraph.cdxweb";
if (!theModel.Save (aModelPath, theWriterParams)) {
std::cerr << std::endl << "ERROR: Failed to export " << aModelPath << ". Exiting" << std::endl;
return MTKConverter_RC_ExportError;
}
Base_UTF16String aThumbnailPath = theFolderPath + "/thumbnail.png";
if (!CreateOriginModelThumbnail (aThumbnailPath, theModel)) {
std::cerr << std::endl << "ERROR: Failed to create thumbnail " << aThumbnailPath << ". Exiting" << std::endl;
return MTKConverter_RC_ExportError;
}
A unfolded representation, if the SheetMetal process was performed also will be converted to *.cdxweb format and saved.
if (!theProcessModel.IsEmpty()) {
Base_UTF16String aProcessModelPath = theFolderPath + "/" + theProcessModel.Name() + ".cdxweb" + "/scenegraph.cdxweb";
if (!theProcessModel.Save (aProcessModelPath, theWriterParams)) {
std::cerr << std::endl << "ERROR: Failed to export " << aProcessModelPath << ". Exiting" << std::endl;
return MTKConverter_RC_ExportError;
}
}
A result of processing will be saved to a json file with the custom MTKConverter_Report
class. However, other premade solutions can be used too.
Base_UTF16String aJsonPath = theFolderPath + "/process_data.json";
if (!theReport.WriteToJSON (aJsonPath)) {
std::cerr << std::endl << "ERROR: Failed to create JSON file " << aJsonPath << ". Exiting" << std::endl;
return MTKConverter_RC_ExportError;
}
return MTKConverter_RC_OK;
}
Most of MTKConverter_Report
methods were designed to generate a json file itself, but there are several distinct methods:
-
WriteFeatures
run sorts and generates a text representation of features.
-
SortFeatures
sorts and groups features to make an output compact. The MTKBase_FeatureComparator
was used for comparison of features by types and parameters. An order of features is preserved with a map.
-
GetShapesId
gets the id of a Shape for a BRepRepresentation. A relative Shape of converted model can be found with the Id.
-
Methods like AddShapeFeature
/ AddDrillingIssue
/ etc. make a text representation of features with their relative parameters.
All features have the same to text export pattern, therefore only the example for Machining_Countersink was present.
else if (aFeature.IsOfType<Machining_Countersink>()) {
const auto& aCountersink = static_cast<const Machining_Countersink&> (aFeature);
auto aFeatureData = WriteFeatureDataToString (
"Radius", "mm", aCountersink.Radius(),
"Depth", "mm", aCountersink.Depth(),
"Axis", "", aCountersink.Axis().Axis(),
theShapeIdVector);
theManager.AddGroupData ("Countersink(s)", "(55, 125, 34)", aFeatureData, theCount);
}
Example output
Below are outputs for different processes.
Machining Milling
The ./examples/models/Fresamento_CAM1_v3.stp
model can be used to run machining_milling
process.
Output
Original Model
|
Model Thumbnail
|
{
"version": "1",
"parts": [
{
"partId": "e31092b7-fc4e-4c02-8021-c0bbbcd21bfa",
"process": "CNC Machining Milling",
"featureRecognition": {
"name": "Feature Recognition",
"totalFeatureCount": "51",
"featureGroups": [
{
"name": "Concave Fillet Edge Milling Face(s)",
"color": "(129, 127, 38)",
"totalGroupFeatureCount": "14",
"subGroupCount": "1",
"subGroups": [
{
"parametersCount": "1",
"parameters": [
{
"name": "Radius",
"units": "mm",
"value": "5.00"
}
],
"featureCount": "14",
"features": [
{
"shapeIDCount": "1",
"shapeIDs": [
{
"id": "555"
}
]
},
...
{
"shapeIDCount": "1",
"shapeIDs": [
{
"id": "669"
}
]
}
]
}
]
},
...
"dfm": {
"name": "Design for Manufacturing",
"totalFeatureCount": "23",
"featureGroups": [
{
"name": "Deep Hole(s)",
"color": "(0, 35, 245)",
"totalGroupFeatureCount": "4",
"subGroupCount": "1",
"subGroups": [
{
"parametersCount": "2",
"parameters": [
{
"name": "Expected Maximum Depth",
"units": "mm",
"value": "29.84"
},
{
"name": "Actual Depth",
"units": "mm",
"value": "31.32"
}
],
"featureCount": "4",
"features": [
{
"shapeIDCount": "2",
"shapeIDs": [
{
"id": "435"
},
{
"id": "423"
}
]
},
{
"shapeIDCount": "2",
"shapeIDs": [
{
"id": "450"
},
{
"id": "438"
}
]
},
{
"shapeIDCount": "2",
"shapeIDs": [
{
"id": "465"
},
{
"id": "453"
}
]
},
{
"shapeIDCount": "2",
"shapeIDs": [
{
"id": "480"
},
{
"id": "468"
}
]
}
]
}
]
},
...
Machining Turning
The ./examples/models/senthi.step
model can be used to run machining_turning
process. The processing result has the same structure as for a Machining milling, thus it was omitted.
Output
Original Model
|
Model Thumbnail
|
Sheet Metal
The ./examples/models/Part2.stp
is suitable to run SheetMetal process. The first part of a json file is the same as in Machining milling and turning, but it also contains the infromation about unfolding analysis.
Output
Original Model
|
Unfolded Model
|
Model Thumbnail
|
...
"featureRecognitionUnfolded": {
"name": "Feature Recognition",
"parametersCount": "3",
"parameters": [
{
"name": "Length",
"units": "mm",
"value": "220.71"
},
{
"name": "Width",
"units": "mm",
"value": "167.84"
},
{
"name": "Thickness",
"units": "mm",
"value": "1.00"
}
]
},
"dfmUnfolded": {
"name": "Design for Manufacturing",
"totalFeatureCount": "1",
"featureGroups": [
{
"name": "Non Standard Sheet Size(s)",
"color": "(0, 0, 0)",
"totalGroupFeatureCount": "1",
"subGroupCount": "1",
"subGroups": [
{
"parametersCount": "2",
"parameters": [
{
"name": "Nearest Standard Size (LxW)",
"units": "mm",
"value": "300.00 x 200.00"
},
{
"name": "Actual Size (LxW)",
"units": "mm",
"value": "220.71 x 167.84"
}
],
"featureCount": "1",
"features": [
{
"shapeIDCount": "0",
"shapeIDs": []
}
]
}
]
}
]
}
}
]
}
Wall Thickness
The ./examples/models/barrel.stp
model can be used to run wall_thickness
process.
Output
Converted Model
|
Model Thumbnail
|
{
"version": "1",
"parts": [
{
"partId": "9b2c8245-0130-4065-8715-2c2abd6ecafe",
"process": "Wall Thickness Analysis",
"minThickness": {
"name": "Minimum Thickness",
"units": "mm",
"value": "4.97",
"firstPoint": "(-45.10, -2.48, -7.23)",
"secondPoint": "(-49.60, -4.58, -7.24)"
},
"maxThickness": {
"name": "Maximum Thickness",
"units": "mm",
"value": "10.00",
"firstPoint": "(-43.66, -11.05, 410.00)",
"secondPoint": "(-43.66, -11.05, 400.00)"
}
}
]
}
Files