#ifndef _FeatureGroup_HeaderFile
#define _FeatureGroup_HeaderFile
#include <cadex/Geom/Direction.hxx>
#include <cadex/MTKBase_Feature.hxx>
#include <cadex/MTKBase_FeatureComparator.hxx>
#include <algorithm>
#include <array>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <sstream>
#include <vector>
using namespace std;
typedef std::pair<double, double> PairType;
typedef std::array<double, 3> ArrayType;
inline std::ostream& operator<< (std::ostream& theStream, const PairType& thePair)
{
return theStream << thePair.first << " x " << thePair.second;
}
inline std::ostream& operator<< (std::ostream& theStream, const ArrayType& theArray)
{
return theStream << theArray[0] << " x " << theArray[1] << " x " << theArray[2];
}
inline std::ostream& operator<< (std::ostream& theStream, const Geom::Direction& theDir)
{
stringstream aStream;
aStream << setprecision(2) << fixed << "(" << theDir.X() << ", " << theDir.Y() << ", " << theDir.Z() << ")";
return theStream << aStream.str();
}
class FeatureGroupManager
{
public:
void AddFeature (const char* theGroupName,
const char* theSubgroupName,
bool theHasParameters,
const MTKBase_Feature& theFeature)
{
auto aRes = std::find_if (myGroups.begin(), myGroups.end(),
[&] (const FeatureGroup& theGroup) { return theGroup.myName == theGroupName; });
if (aRes == myGroups.end()) {
aRes = myGroups.insert (aRes, FeatureGroup (theGroupName, theSubgroupName, theHasParameters));
}
auto& aGroup = *aRes;
++aGroup.myFeatureSubgroups[theFeature];
}
void Print (const char* theFeatureType, function<void (MTKBase_Feature)> thePrintFeatureParameters)
{
sort (myGroups.begin(), myGroups.end(), FeatureGroupComparator());
cout << setprecision(6);
size_t aTotalCount = 0;
for (const auto& aFeatureGroup : myGroups) {
size_t aFeatureCount = aFeatureGroup.FeatureCount();
aTotalCount += aFeatureCount;
cout << " " << aFeatureGroup.myName << ": " << aFeatureCount << endl;
if (!aFeatureGroup.myHasParameters) {
continue;
}
const char* aSubgroupName = aFeatureGroup.mySubgroupName.c_str();
for (const auto& aFeatureSubgroup : aFeatureGroup.myFeatureSubgroups) {
cout << " " << aFeatureSubgroup.second << " " << aSubgroupName << " with" << endl;
thePrintFeatureParameters (aFeatureSubgroup.first);
}
}
cout << "\n Total " << theFeatureType << ": " << aTotalCount << "\n" << endl;
}
template <typename T>
static void PrintFeatureParameter (const char* theName, const T& theValue, const char* theUnits)
{
cout << " " << theName << ": " << theValue << " " << theUnits << endl;
}
private:
class FeatureGroup
{
public:
FeatureGroup (const std::string& theName, const std::string& theSubgroupName, bool theHasParameters) :
myName (theName), mySubgroupName (theSubgroupName), myHasParameters (theHasParameters)
{}
size_t FeatureCount() const
{
size_t aCount = 0;
for (const auto& aFeatureSubgroup : myFeatureSubgroups) {
aCount += aFeatureSubgroup.second;
}
return aCount;
}
string myName;
string mySubgroupName;
bool myHasParameters;
map<MTKBase_Feature, size_t, MTKBase_FeatureComparator> myFeatureSubgroups;
};
class FeatureGroupComparator
{
public:
bool operator() (const FeatureGroup& theA, const FeatureGroup& theB) const
{
const auto& anAName = theA.myName;
const auto& aBName = theB.myName;
if (anAName == aBName) {
return false;
}
const auto& anAFeatureSubgroups = theA.myFeatureSubgroups;
const auto& aBFeatureSubgroups = theB.myFeatureSubgroups;
if (anAFeatureSubgroups.empty() || aBFeatureSubgroups.empty()) {
return anAName < aBName;
}
return MTKBase_FeatureComparator() (anAFeatureSubgroups.begin()->first,
aBFeatureSubgroups.begin()->first);
}
};
vector<FeatureGroup> myGroups;
};
#endif
Contains classes, namespaces, enums, types, and global functions related to Manufacturing Toolkit.
#ifndef _ShapeProcessor_HeaderFile
#define _ShapeProcessor_HeaderFile
#include <cadex/Base/UTF16String.hxx>
#include <cadex/ModelData/Body.hxx>
#include <cadex/ModelData/Model.hxx>
#include <cadex/ModelData/Part.hxx>
#include <cadex/ModelData/Shell.hxx>
#include <cadex/ModelData/Solid.hxx>
#include <cadex/WallThickness_Data.hxx>
#include <iostream>
using namespace std;
class ShapeProcessor : public ModelData::ModelElementVoidVisitor
{
public:
void operator() (const ModelData::Part& thePart) override
{
auto aPartName = thePart.Name().IsEmpty() ? "noname" : thePart.Name();
size_t aBodyNumber = 0;
const auto& aBodies = thePart.Bodies();
for (const auto& aBody : aBodies) {
ModelData::ShapeIterator aShapeIt (aBody);
while (aShapeIt.HasNext()) {
const auto& aShape = aShapeIt.Next();
if (aShape.Type() == ModelData::ShapeType::Solid) {
cout << "Part #" << myPartIndex << " [\"" << aPartName << "\"] - solid #" << std::to_string (aBodyNumber) << " has:" << endl;
ProcessSolid (ModelData::Solid::Cast (aShape));
} else if (aShape.Type() == ModelData::ShapeType::Shell) {
cout << "Part #" << myPartIndex << " [\"" << aPartName << "\"] - shell #" << std::to_string (aBodyNumber) << " has:" << endl;
ProcessShell (ModelData::Shell::Cast (aShape));
}
}
++aBodyNumber;
}
++myPartIndex;
}
virtual void ProcessSolid (const ModelData::Solid& theSolid) = 0;
virtual void ProcessShell (const ModelData::Shell& theShell) = 0;
private:
size_t myPartIndex = 0;
};
class SolidProcessor : public ModelData::ModelElementVoidVisitor
{
public:
void operator() (const ModelData::Part& thePart) override
{
auto aPartName = thePart.Name().IsEmpty() ? "noname" : thePart.Name();
size_t aBodyNumber = 0;
const auto& aBodies = thePart.Bodies();
for (const auto& aBody : aBodies) {
ModelData::ShapeIterator aShapeIt (aBody);
while (aShapeIt.HasNext()) {
const auto& aShape = aShapeIt.Next();
if (aShape.Type() == ModelData::ShapeType::Solid) {
cout << "Part #" << myPartIndex << " [\"" << aPartName << "\"] - solid #" << std::to_string (aBodyNumber++) << " has:" << endl;
ProcessSolid (ModelData::Solid::Cast (aShape));
}
}
}
++myPartIndex;
}
virtual void ProcessSolid (const ModelData::Solid& theSolid) = 0;
private:
size_t myPartIndex = 0;
};
class SolidAndMeshProcessor : public ModelData::ModelElementVoidVisitor
{
public:
void operator() (const ModelData::Part& thePart) override
{
auto aPartName = thePart.Name().IsEmpty() ? "noname" : thePart.Name();
size_t aBodyNumber = 0;
const auto& aBodies = thePart.Bodies();
for (const auto& aBody : aBodies) {
ModelData::ShapeIterator aShapeIt (aBody);
while (aShapeIt.HasNext()) {
const auto& aShape = aShapeIt.Next();
if (aShape.Type() == ModelData::ShapeType::Solid) {
cout << "Part #" << myPartIndex << " [\"" << aPartName << "\"] - solid #" << std::to_string (aBodyNumber++) << " has:" << endl;
ProcessSolid (ModelData::Solid::Cast (aShape), aPartName, aBodyNumber);
}
}
}
++myPartIndex;
}
virtual void ProcessSolid (const ModelData::Solid& theSolid,
const UTF16String& thePartName, size_t theShapeIndex) = 0;
protected:
size_t myPartIndex = 0;
};
#endif
#include <cadex/Geom/Axis1d.hxx>
#include <cadex/Geom/Axis3d.hxx>
#include <cadex/LicenseManager_Activate.h>
#include <cadex/Machining_Bore.hxx>
#include <cadex/Machining_Countersink.hxx>
#include <cadex/Machining_Face.hxx>
#include <cadex/Machining_FaceType.hxx>
#include <cadex/Machining_FeatureRecognizer.hxx>
#include <cadex/Machining_FeatureRecognizerParameters.hxx>
#include <cadex/Machining_Groove.hxx>
#include <cadex/Machining_Hole.hxx>
#include <cadex/Machining_HoleType.hxx>
#include <cadex/Machining_OperationType.hxx>
#include <cadex/Machining_Pocket.hxx>
#include <cadex/Machining_SteppedHole.hxx>
#include <cadex/Machining_ThreadedHole.hxx>
#include <cadex/Machining_TurningFace.hxx>
#include <cadex/Machining_TurningGroove.hxx>
#include <cadex/ModelData/Model.hxx>
#include <cadex/ModelData/ModelReader.hxx>
#include <cadex/MTKBase_Boss.hxx>
#include <cadex/MTKBase_Feature.hxx>
#include <cadex/MTKBase_FeatureList.hxx>
#include <unordered_map>
#include "../../helpers/feature_group.hxx"
#include "../../helpers/shape_processor.hxx"
#include "../../mtk_license.cxx"
using namespace std;
const char* FaceTypeToString (Machining_FaceType theType)
{
switch (theType) {
case Machining_FT_FlatFaceMilled: return "Flat Face Milled Face(s)";
case Machining_FT_FlatSideMilled: return "Flat Side Milled Face(s)";
case Machining_FT_CurvedMilled: return "Curved Milled Face(s)";
case Machining_FT_CircularMilled: return "Circular Milled Face(s)";
case Machining_FT_Deburr: return "Deburr Face(s)";
case Machining_FT_ConvexProfileEdgeMilling: return "Convex Profile Edge Milling Face(s)";
case Machining_FT_ConcaveFilletEdgeMilling: return "Concave Fillet Edge Milling Face(s)";
case Machining_FT_FlatMilled: return "Flat Milled Face(s)";
case Machining_FT_TurnDiameter: return "Turn Diameter Face(s)";
case Machining_FT_TurnForm: return "Turn Form Face(s)";
case Machining_FT_TurnFace: return "Turn Face Face(s)";
default:
break;
}
return "Face(s)";
}
const char* PocketTypeToString (Machining_PocketType theType)
{
switch (theType) {
case Machining_PT_Closed: return "Closed Pocket(s)";
case Machining_PT_Open: return "Open Pocket(s)";
case Machining_PT_Through: return "Through Pocket(s)";
default:
break;
}
return "Pocket(s)";
}
const char* HoleTypeToString (Machining_HoleType theType)
{
switch (theType) {
case Machining_HT_Through: return "Through Hole(s)";
case Machining_HT_FlatBottom: return "Flat Bottom Hole(s)";
case Machining_HT_Blind: return "Blind Hole(s)";
case Machining_HT_Partial: return "Partial Hole(s)";
default:
break;
}
return "Hole(s)";
}
const char* TurningGrooveTypeToString (Machining_TurningGrooveType theType)
{
switch (theType) {
case Machining_TGT_OuterDiameter: return "Outer Diameter Groove(s)";
case Machining_TGT_InnerDiameter: return "Inner Diameter Groove(s)";
case Machining_TGT_EndFace: return "End Face Groove(s)";
default:
break;
}
return "Turning Groove(s)";
}
void PrintFeatures (const MTKBase_FeatureList& theFeatureList)
{
FeatureGroupManager aManager;
std::function<void (MTKBase_FeatureList)> GroupByParameters = [&] (const MTKBase_FeatureList& theFeatures) -> void {
for (size_t i = 0; i < theFeatures.Size(); i++) {
const auto& aFeature = theFeatures[i];
if (aFeature.IsOfType<Machining_TurningFace>()) {
const auto& aTurningFace = static_cast<const Machining_TurningFace&> (aFeature);
aManager.AddFeature (FaceTypeToString (aTurningFace.Type()), "Turning Face(s)", true, aFeature);
} else if (aFeature.IsOfType<Machining_Face>()) {
const auto& aFace = static_cast<const Machining_Face&> (aFeature);
aManager.AddFeature (FaceTypeToString (aFace.Type()), "", false, aFeature);
} else if (aFeature.IsOfType<Machining_Countersink>()) {
aManager.AddFeature ("Countersink(s)", "Countersink(s)", true, aFeature);
} else if (aFeature.IsOfType<Machining_ThreadedHole>()) {
const auto& aThreadedHole = static_cast<const Machining_ThreadedHole&> (aFeature);
std::string aGroupName = std::string ("Threaded ") + HoleTypeToString (aThreadedHole.Type());
aManager.AddFeature (aGroupName.c_str(), "Threaded Hole(s)", true, aFeature);
} else if (aFeature.IsOfType<Machining_Hole>()) {
const auto& aHole = static_cast<const Machining_Hole&> (aFeature);
aManager.AddFeature (HoleTypeToString (aHole.Type()), "Hole(s)", true, aFeature);
} else if (aFeature.IsOfType<Machining_SteppedHole>()) {
aManager.AddFeature ("Stepped Hole(s)", "Stepped Hole(s)", true, aFeature);
} else if (aFeature.IsOfType<Machining_Pocket>()) {
const auto& aPocket = static_cast<const Machining_Pocket&> (aFeature);
aManager.AddFeature (PocketTypeToString (aPocket.Type()), "", true, aFeature);
} else if (aFeature.IsOfType<MTKBase_Boss>()) {
aManager.AddFeature ("Boss(es)", "Boss(es)", true, aFeature);
} else if (aFeature.IsOfType<Machining_TurningGroove>()) {
const auto& aTurningGroove = static_cast<const Machining_TurningGroove&> (aFeature);
aManager.AddFeature (TurningGrooveTypeToString (aTurningGroove.Type()),
"", true, aFeature);
} else if (aFeature.IsOfType<Machining_Bore>()) {
aManager.AddFeature ("Bore(s)", "", true, aFeature);
}
}
};
GroupByParameters (theFeatureList);
auto PrintFeatureParameters = [] (const MTKBase_Feature& theFeature)
{
if (theFeature.IsOfType<Machining_TurningFace>()) {
const auto& aTurningFace = static_cast<const Machining_TurningFace&> (theFeature);
FeatureGroupManager::PrintFeatureParameter ("radius", aTurningFace.Radius(), "mm");
} else if (theFeature.IsOfType<Machining_Face>()) {
} else if (theFeature.IsOfType<Machining_Countersink>()) {
const auto& aCountersink = static_cast<const Machining_Countersink&> (theFeature);
FeatureGroupManager::PrintFeatureParameter ("radius", aCountersink.Radius(), "mm");
FeatureGroupManager::PrintFeatureParameter ("depth", aCountersink.Depth(), "mm");
FeatureGroupManager::PrintFeatureParameter ("axis", aCountersink.Axis().Axis(), "");
} else if (theFeature.IsOfType<Machining_ThreadedHole>()) {
const auto& aThreadedHole = static_cast<const Machining_ThreadedHole&> (theFeature);
FeatureGroupManager::PrintFeatureParameter ("minor radius", aThreadedHole.MinorRadius(), "mm");
FeatureGroupManager::PrintFeatureParameter ("major radius", aThreadedHole.MajorRadius(), "mm");
FeatureGroupManager::PrintFeatureParameter ("thread length", aThreadedHole.ThreadLength(), "mm");
FeatureGroupManager::PrintFeatureParameter ("pitch", aThreadedHole.Pitch(), "mm");
FeatureGroupManager::PrintFeatureParameter ("depth", aThreadedHole.Depth(), "mm");
FeatureGroupManager::PrintFeatureParameter ("axis", aThreadedHole.Axis().Axis(), "");
} else if (theFeature.IsOfType<Machining_Hole>()) {
const auto& aHole = static_cast<const Machining_Hole&> (theFeature);
FeatureGroupManager::PrintFeatureParameter ("radius", aHole.Radius(), "mm");
FeatureGroupManager::PrintFeatureParameter ("depth", aHole.Depth(), "mm");
FeatureGroupManager::PrintFeatureParameter ("axis", aHole.Axis().Axis(), "");
} else if (theFeature.IsOfType<Machining_SteppedHole>()) {
const auto& aHole = static_cast<const Machining_SteppedHole&> (theFeature);
FeatureGroupManager::PrintFeatureParameter ("depth", aHole.Depth(), "mm");
} else if (theFeature.IsOfType<Machining_Pocket>()) {
const auto& aPocket = static_cast<const Machining_Pocket&> (theFeature);
FeatureGroupManager::PrintFeatureParameter ("length", aPocket.Length(), "mm");
FeatureGroupManager::PrintFeatureParameter ("width", aPocket.Width(), "mm");
FeatureGroupManager::PrintFeatureParameter ("depth", aPocket.Depth(), "mm");
FeatureGroupManager::PrintFeatureParameter ("axis", aPocket.Axis().Direction(), "");
} else if (theFeature.IsOfType<MTKBase_Boss>()) {
const auto& aBoss = static_cast<const MTKBase_Boss&> (theFeature);
FeatureGroupManager::PrintFeatureParameter ("length", aBoss.Length(), "mm");
FeatureGroupManager::PrintFeatureParameter ("width", aBoss.Width(), "mm");
FeatureGroupManager::PrintFeatureParameter ("height", aBoss.Height(), "mm");
} else if (theFeature.IsOfType<Machining_TurningGroove>()) {
const auto& aTurningGroove = static_cast<const Machining_TurningGroove&> (theFeature);
FeatureGroupManager::PrintFeatureParameter ("radius", aTurningGroove.Radius(), "mm");
FeatureGroupManager::PrintFeatureParameter ("depth", aTurningGroove.Depth(), "mm");
FeatureGroupManager::PrintFeatureParameter ("width", aTurningGroove.Width(), "mm");
} else if (theFeature.IsOfType<Machining_Bore>()) {
const auto& aBore = static_cast<const Machining_Bore&> (theFeature);
FeatureGroupManager::PrintFeatureParameter ("radius", aBore.Radius(), "mm");
FeatureGroupManager::PrintFeatureParameter ("depth", aBore.Depth(), "mm");
}
};
aManager.Print ("features", PrintFeatureParameters);
}
class PartProcessor : public SolidProcessor
{
public:
PartProcessor (Machining_OperationType theOperation) : myOperation (theOperation)
{}
void ProcessSolid (const ModelData::Solid& theSolid) override
{
Machining_FeatureRecognizer aRecognizer;
aRecognizer.Parameters().SetOperation (myOperation);
auto aFeatureList = aRecognizer.Perform (theSolid);
PrintFeatures (aFeatureList);
}
private:
Machining_OperationType myOperation = Machining_OT_Undefined;
};
void PrintSupportedOperations()
{
cerr << "Supported operations:" << endl;
cerr << " milling:\t CNC Machining Milling feature recognition" << endl;
cerr << " turning:\t CNC Machining Lathe+Milling feature recognition" << endl;
}
Machining_OperationType OperationType (std::string theOperationStr)
{
static std::unordered_map<std::string, Machining_OperationType> aProcessMap
{
{"milling", Machining_OT_Milling},
{"turning", Machining_OT_LatheMilling}
};
auto aRes = aProcessMap.find (theOperationStr);
if (aRes != aProcessMap.end()) {
return aRes->second;
}
return Machining_OT_Undefined;
}
int main (int argc, char* argv[])
{
auto aKey = MTKLicenseKey::Value();
if (!CADExLicense_Activate (aKey)) {
cerr << "Failed to activate Manufacturing Toolkit license." << endl;
return 1;
}
if (argc != 3) {
cerr << "Usage: " << argv[0] << " <input_file> <operation>, where:" << endl;
cerr << " <input_file> is a name of the file to be read" << endl;
cerr << " <operation> is a name of desired machining operation" << endl << endl;
PrintSupportedOperations();
return 1;
}
const char* aSource = argv[1];
ModelData::Model aModel;
ModelData::ModelReader aReader;
if (!aReader.Read (aSource, aModel)) {
cerr << "Failed to read the file " << aSource << endl;
return 1;
}
cout << "Model: " << aModel.Name() << "\n" << endl;
const char* anOperationStr = argv[2];
auto anOperation = OperationType (anOperationStr);
if (anOperation == Machining_OT_Undefined) {
cerr << "Unsupported operation - " << anOperationStr << endl;
cerr << "Please use one of the following." << endl;
PrintSupportedOperations();
return 1;
}
PartProcessor aPartProcessor (anOperation);
ModelData::ModelElementUniqueVisitor aVisitor (aPartProcessor);
aModel.Accept (aVisitor);
return 0;
}