/////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2002-2025, Open Design Alliance (the "Alliance"). // All rights reserved. // // This software and its documentation and related materials are owned by // the Alliance. The software may only be incorporated into application // programs owned by members of the Alliance, subject to a signed // Membership Agreement and Supplemental Software License Agreement with the // Alliance. The structure and organization of this software are the valuable // trade secrets of the Alliance and its suppliers. The software is also // protected by copyright law and international treaty provisions. Application // programs incorporating this software must include the following statement // with their copyright notices: // // This application incorporates Open Design Alliance software pursuant to a license // agreement with Open Design Alliance. // Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance. // All rights reserved. // // By use of this software, its documentation or related materials, you // acknowledge and accept the above terms. /////////////////////////////////////////////////////////////////////////////// #include "OdaCommon.h" #include #include #include "ExIgesTutorial_06.h" #include "RxValue.h" #include "Ge/GeExtents3d.h" #include "IgesEntities.h" #include "IgesSelectTypes.h" #include // Include specific CSG entity headers #include "blockAutoImpl.h" #include "right_angular_wedgeAutoImpl.h" #include "right_circular_cylinderAutoImpl.h" #include "right_circular_cone_frustumAutoImpl.h" #include "sphereAutoImpl.h" #include "torusAutoImpl.h" #include "solid_of_revolutionAutoImpl.h" #include "solid_of_linear_extrusionAutoImpl.h" #include "ellipsoidAutoImpl.h" #include "boolean_treeAutoImpl.h" // For Boolean operations #include "solid_assemblyAutoImpl.h" // For combining solid components #include "solid_instanceAutoImpl.h" // For referencing solid components // Required for odPrintConsoleString #include "ExPrintConsole.h" using namespace OdDAI; namespace { // Helper to set common geometric data for IGES entities void setCsgGeometricData(Iges::constructive_solid_geometryPtr pCSG, OdAnsiString label, int level, int subscript, Iges::blank_status blank, Iges::color_number color) { pCSG->setlabel(label); pCSG->level().setint_val(level); pCSG->setsubscript(subscript); pCSG->setblank(blank); pCSG->color().setcolor_number(color); } void setGeometricData(Iges::geometricPtr pGeometric, OdAnsiString label, int level, int subscript, Iges::blank_status blank, Iges::color_number color) { pGeometric->setlabel(label); pGeometric->level().setint_val(level); pGeometric->setsubscript(subscript); pGeometric->setblank(blank); pGeometric->color().setcolor_number(color); } // Create Block CSG object OdDAIObjectId createBlock(OdDAI::Model* pModel, double x, double y, double z, double lx, double ly, double lz) { Iges::blockPtr pBlock = Iges::block::createObject(pModel); setCsgGeometricData(pBlock, "Block", 0, 0, Iges::kblank_status_visible, Iges::kcolor_number_blue); // Set block dimensions and origin using the correct public setters from blockAutoImpl.h pBlock->setx1(x); pBlock->sety1(y); pBlock->setz1(z); pBlock->setlx(lx); pBlock->setly(ly); pBlock->setlz(lz); // Set default local X and Z axis vectors as per IGES standard defaults (identity matrix orientation) pBlock->seti1(1.0); pBlock->setj1(0.0); pBlock->setk1(0.0); pBlock->seti2(0.0); pBlock->setj2(0.0); pBlock->setk2(1.0); pBlock->setsubordinate(Iges::ksubordinate_switch_independent); return pBlock->id(); } // Create Right Circular Cylinder CSG object OdDAIObjectId createRightCircularCylinder(OdDAI::Model* pModel, double x, double y, double z, double h, double r, double i, double j, double k) { Iges::right_circular_cylinderPtr pCylinder = Iges::right_circular_cylinder::createObject(pModel); setCsgGeometricData(pCylinder, "Cylinder", 0, 0, Iges::kblank_status_visible, Iges::kcolor_number_green); pCylinder->setx1(x); pCylinder->sety1(y); pCylinder->setz1(z); pCylinder->seth(h); pCylinder->setr(r); pCylinder->seti1(i); pCylinder->setj1(j); pCylinder->setk1(k); pCylinder->setsubordinate(Iges::ksubordinate_switch_independent); return pCylinder->id(); } // Create Sphere CSG object OdDAIObjectId createSphere(OdDAI::Model* pModel, double r, double x, double y, double z) { Iges::spherePtr pSphere = Iges::sphere::createObject(pModel); setCsgGeometricData(pSphere, "Sphere", 0, 0, Iges::kblank_status_visible, Iges::kcolor_number_red); pSphere->setr(r); pSphere->setx1(x); pSphere->sety1(y); pSphere->setz1(z); pSphere->setsubordinate(Iges::ksubordinate_switch_independent); return pSphere->id(); } // Create Torus CSG object OdDAIObjectId createTorus(OdDAI::Model* pModel, double r1, double r2, double x, double y, double z, double i, double j, double k) { Iges::torusPtr pTorus = Iges::torus::createObject(pModel); setCsgGeometricData(pTorus, "Torus", 0, 0, Iges::kblank_status_visible, Iges::kcolor_number_cyan); pTorus->setr1(r1); // Major radius pTorus->setr2(r2); // Minor radius pTorus->setx1(x); pTorus->sety1(y); pTorus->setz1(z); pTorus->seti1(i); pTorus->setj1(j); pTorus->setk1(k); pTorus->setsubordinate(Iges::ksubordinate_switch_independent); return pTorus->id(); } // Create Solid of Linear Extrusion CSG object OdDAIObjectId createSolidOfLinearExtrusion(OdDAI::Model* pModel, const OdDAIObjectId& baseCurveId, double l, double i, double j, double k) { Iges::solid_of_linear_extrusionPtr pSolid = Iges::solid_of_linear_extrusion::createObject(pModel); setCsgGeometricData(pSolid, "Linear Extrusion", 0, 0, Iges::kblank_status_visible, Iges::kcolor_number_magenta); pSolid->setptr(baseCurveId); // Pointer to the base curve (e.g., planar curve) pSolid->setl(l); // Length of extrusion pSolid->seti1(i); // Extrusion vector X pSolid->setj1(j); // Extrusion vector Y pSolid->setk1(k); // Extrusion vector Z pSolid->setsubordinate(Iges::ksubordinate_switch_independent); return pSolid->id(); } // Create Solid of Revolution CSG object OdDAIObjectId createSolidOfRevolution(OdDAI::Model* pModel, int form, const OdDAIObjectId& generatorCurveId, double f, double x, double y, double z, double i, double j, double k) { Iges::solid_of_revolutionPtr pSolid = Iges::solid_of_revolution::createObject(pModel); setCsgGeometricData(pSolid, "Solid of Revolution", 0, 0, Iges::kblank_status_visible, Iges::kcolor_number_yellow); pSolid->setform(form); // Form code: 0=revolved surface, 1=solid pSolid->setptr(generatorCurveId); // Pointer to the generator curve pSolid->setf(f); // Angle of revolution (radians) pSolid->setx1(x); // Axis point X pSolid->sety1(y); // Axis point Y pSolid->setz1(z); // Axis point Z pSolid->seti1(i); // Axis vector X pSolid->setj1(j); // Axis vector Y pSolid->setk1(k); // Axis vector Z pSolid->setsubordinate(Iges::ksubordinate_switch_independent); return pSolid->id(); } // Helper to create a Boolean Tree entity OdDAIObjectId createBooleanTree(OdDAI::Model* pModel, Iges::boolean_op_code op, const OdDAIObjectId& operand1, const OdDAIObjectId& operand2) { Iges::boolean_treePtr pBooleanTree = Iges::boolean_tree::createObject(pModel); setCsgGeometricData(pBooleanTree, "BooleanResult", 0, 0, Iges::kblank_status_visible, Iges::kcolor_number_white); //pBooleanTree->setboolean_operation(op); // Create solid_instance entities for the operands Iges::solid_instancePtr pSolidInstance1 = Iges::solid_instance::createObject(pModel); pSolidInstance1->setsubordinate(Iges::ksubordinate_switch_physicallyDependent); pSolidInstance1->setused(Iges::kuse_flag_geometry); pSolidInstance1->sethierarchy(Iges::khierarchy_flag_individual); pSolidInstance1->setptr(operand1); Iges::solid_instancePtr pSolidInstance2 = Iges::solid_instance::createObject(pModel); pSolidInstance2->setsubordinate(Iges::ksubordinate_switch_physicallyDependent); pSolidInstance2->setused(Iges::kuse_flag_geometry); pSolidInstance2->sethierarchy(Iges::khierarchy_flag_individual); pSolidInstance2->setptr(operand2); OdDAI::ListOfSelect& operands = pBooleanTree->operands(); operands.createEmpty(); operands.putByIndex(0, OdRxValue(OdDAIObjectId(pSolidInstance1->id()))); operands.putByIndex(1, OdRxValue(OdDAIObjectId(pSolidInstance2->id()))); OdDAI::Select generatedSelect = operands.generateAggrItem(); if (generatedSelect.underlyingTypeName("boolean_op_code")) { switch (op) { case Iges::kboolean_op_code_union: generatedSelect.setEnum("union"); break; case Iges::kboolean_op_code_difference: generatedSelect.setEnum("difference"); break; case Iges::kboolean_op_code_intersection: generatedSelect.setEnum("intersection"); break; default:; } if (generatedSelect.exists()) operands.putByIndex(2, generatedSelect); } pBooleanTree->setsubordinate(Iges::ksubordinate_switch_independent); return pBooleanTree->id(); } // Function to create an elliptic arc as a base for Solid of Linear Extrusion OdDAIObjectId createEllipArc(OdDAI::Model* pModel, double x1, double y1, double z1, double r1, double r2) { Iges::conic_arcPtr pEllipArc = Iges::conic_arc::createObject(pModel); setGeometricData(pEllipArc, "BaseEllipArc", 0, 0, Iges::kblank_status_visible, Iges::kcolor_number_black); OdGePoint3d center(x1, y1, z1); OdGeVector3d majorAxis(1., 0., 0.); OdGeVector3d minorAxis(0., 1., 0.); pEllipArc->setFrom(OdGeEllipArc3d(center, majorAxis, minorAxis, r1, r2)); pEllipArc->setsubordinate(Iges::ksubordinate_switch_physicallyDependent); pEllipArc->setused(Iges::kuse_flag_geometry); pEllipArc->line_font().setline_pattern(Iges::kline_pattern_none); pEllipArc->setline_weight(0); return pEllipArc->id(); } // Function to create a circular arc as a base for Solid of Revolution OdDAIObjectId createCircularArc(OdDAI::Model* pModel, double zt, double x1, double y1, double x2, double y2, double x3, double y3) { Iges::circular_arcPtr pCircularArc = Iges::circular_arc::createObject(pModel); setGeometricData(pCircularArc, "BaseCircularArc", 0, 0, Iges::kblank_status_visible, Iges::kcolor_number_black); OdGePoint3d center(x1, y1, zt); OdGePoint3d start(x2, y2, zt); OdGePoint3d end(x3, y3, zt); OdGeVector3d normal(OdGeVector3d::kZAxis); OdGeVector3d refVector(OdGeVector3d::kXAxis); double radius = (start - center).length(); double startAngle = (start - center).convert2d().angle(), endAngle = (end - center).convert2d().angle(); OdGeCircArc3d circArc3d(center, normal, refVector, radius, startAngle, endAngle); pCircularArc->setFrom(circArc3d); pCircularArc->setsubordinate(Iges::ksubordinate_switch_physicallyDependent); pCircularArc->setused(Iges::kuse_flag_geometry); pCircularArc->line_font().setline_pattern(Iges::kline_pattern_none); pCircularArc->setline_weight(0); return pCircularArc->id(); } // Helper function to write the IGES file void writeIgesFile(IgesFilePtr igesFile, const OdString& fileName, OdDAIObjectId mainEntityId) { OdDAI::Model* pModel = igesFile->getModel(); Iges::iges_filePtr pFile = Iges::iges_file::createObject(pModel); OdDAI::ListOfOdAnsiString& fileStartSection = pFile->start_section(); fileStartSection.createEmpty(); fileStartSection.addByIndex(0, "Open Design Alliance IGES SDK Tutorial_05"); Iges::globalPtr pGlobal = Iges::global::createObject(pModel); pGlobal->setparameter_delimiter(","); pGlobal->setrecord_delimiter(";"); pGlobal->setnumber_of_binary_bits(32); pGlobal->setsingle_precision_magnitude(38); pGlobal->setsingle_precision_significance(6); pGlobal->setdouble_precision_magnitude(308); pGlobal->setdouble_precision_significance(15); pGlobal->setmodel_space_scale(1.); pGlobal->setunit_flag(Iges::kunitFlag_inches); pGlobal->setunits("IN"); pGlobal->setmax_num_line_weight_gradations(1000); pGlobal->setwidth_max_line_weight(5.); pGlobal->setdate_time_file_generation("20250715.140000"); // Current time pGlobal->setmax_coordinate_value(0.); pGlobal->setauthor("Tutorial_05"); pGlobal->setorganization("Open Design Alliance"); pGlobal->setversion(11); pGlobal->setdrafting_standard_code(Iges::kdraftingStandardCode_none); pGlobal->setdate_time_created_modified("20250715.140000"); // Current time pGlobal->setmilspec("NULL"); pFile->setglobal_section(pGlobal->id()); // Add the main entity to the directory entries if it's not a subordinate //OdDAI::ListOfOdDAIObjectId& directoryEntries = pFile->directory_entries(); //directoryEntries.createEmpty(); //if (!mainEntityId.isNull()) //{ // directoryEntries.addByIndex(0, mainEntityId); //} igesFile->writeFile(fileName); } OdDAIObjectId createRightAngularWedge(OdDAI::Model* pModel, double x, double y, double z, double lx, double ly, double lz, double ltx, double i1, double j1, double k1, double i2, double j2, double k2) { Iges::right_angular_wedgePtr pWedge = Iges::right_angular_wedge::createObject(pModel); setCsgGeometricData(pWedge, "Wedge", 0, 0, Iges::kblank_status_visible, Iges::kcolor_number_red); pWedge->setx1(x); pWedge->sety1(y); pWedge->setz1(z); pWedge->setlx(lx); pWedge->setly(ly); pWedge->setlz(lz); pWedge->setltx(ltx); pWedge->seti1(i1); pWedge->setj1(j1); pWedge->setk1(k1); pWedge->seti2(i2); pWedge->setj2(j2); pWedge->setk2(k2); pWedge->setsubordinate(Iges::ksubordinate_switch_independent); return pWedge->id(); } OdDAIObjectId createRightCircularConeFrustum(OdDAI::Model* pModel, double x, double y, double z, double h, double r1, double r2, double i, double j, double k) { Iges::right_circular_cone_frustumPtr pConeFrustum = Iges::right_circular_cone_frustum::createObject(pModel); setCsgGeometricData(pConeFrustum, "Cone Frustum", 0, 0, Iges::kblank_status_visible, Iges::kcolor_number_cyan); pConeFrustum->setx1(x); pConeFrustum->sety1(y); pConeFrustum->setz1(z); pConeFrustum->seth(h); pConeFrustum->setr1(r1); pConeFrustum->setr2(r2); pConeFrustum->seti1(i); pConeFrustum->setj1(j); pConeFrustum->setk1(k); pConeFrustum->setsubordinate(Iges::ksubordinate_switch_independent); return pConeFrustum->id(); } OdDAIObjectId createEllipsoid(OdDAI::Model* pModel, double lx, double ly, double lz, double x, double y, double z, double i1, double j1, double k1, double i2, double j2, double k2) { Iges::ellipsoidPtr pEllipsoid = Iges::ellipsoid::createObject(pModel); setCsgGeometricData(pEllipsoid, "Ellipsoid", 0, 0, Iges::kblank_status_visible, Iges::kcolor_number_magenta); pEllipsoid->setlx(lx); pEllipsoid->setly(ly); pEllipsoid->setlz(lz); pEllipsoid->setx1(x); pEllipsoid->sety1(y); pEllipsoid->setz1(z); pEllipsoid->seti1(i1); pEllipsoid->setj1(j1); pEllipsoid->setk1(k1); pEllipsoid->seti2(i2); pEllipsoid->setj2(j2); pEllipsoid->setk2(k2); pEllipsoid->setsubordinate(Iges::ksubordinate_switch_independent); return pEllipsoid->id(); } } // namespace Tutorial_06::Tutorial_06(const OdString& applicationName) : BaseIgesTutorial(applicationName) , m_operand1Type(L"Block") , m_operand2Type(L"Cylinder") , m_booleanOperation(L"Union") { m_tutorialArgsParser .add_param( std::make_shared>(m_outputFileName, "outputFileName", "output file name for generated .iges file")); m_tutorialArgsParser .add_param( std::make_shared>(m_operand1Type, "operand1", "Type of the first CSG operand (e.g., Block, Cylinder, Sphere).")); m_tutorialArgsParser .add_param( std::make_shared>(m_operand2Type, "operand2", "Type of the second CSG operand (e.g., Block, Cylinder, Sphere).")); m_tutorialArgsParser .add_param( std::make_shared>(m_booleanOperation, "operation", "Boolean operation (Union, Intersection, Difference).")); m_tutorialArgsParser .add_param( std::make_shared(m_noWait, "-NoWait", "disable \"press any key\" on finish.")); } const std::map> Tutorial_06::csgObjectFactories = { {L"Block", [](OdDAI::Model* pModel) { return createBlock(pModel, 0., 0., 0., 10., 10., 10.); }}, {L"Cylinder", [](OdDAI::Model* pModel) { return createRightCircularCylinder(pModel, 0., 0., 0., 10., 5., 0., 0., 1.); }}, {L"Sphere", [](OdDAI::Model* pModel) { return createSphere(pModel, 5., 0., 0., 0.); }}, {L"Torus", [](OdDAI::Model* pModel) { return createTorus(pModel, 10., 2., 0., 0., 0., 0., 0., 1.); }}, {L"Extrusion", [](OdDAI::Model* pModel) { OdDAIObjectId lineId = createEllipArc(pModel, 0., 0., 0., 7., 5.); return createSolidOfLinearExtrusion(pModel, lineId, 10., 0., 0., 1.); }}, {L"Revolution", [](OdDAI::Model* pModel) { OdDAIObjectId arcId = createCircularArc(pModel, 0., 0., 0., 5., 0., -5., 0.); return createSolidOfRevolution(pModel, 0, arcId, Oda2PI, 0., 0., 0., 1., 0., 0.); }}, {L"Wedge", [](OdDAI::Model* pModel) { return createRightAngularWedge(pModel, 0., 0., 0., 10., 10., 10., 5., 1., 0., 0., 0., 0., 1.); }}, {L"ConeFrustum", [](OdDAI::Model* pModel) { return createRightCircularConeFrustum(pModel, 0., 0., 0., 10., 5., 2., 0., 0., 1.); }}, {L"Ellipsoid", [](OdDAI::Model* pModel) { return createEllipsoid(pModel, 5., 3., 2., 0., 0., 0., 1., 0., 0., 0., 0., 1.); }} }; const std::map> Tutorial_06::csgSecondOperandFactories = { {L"Block", [](OdDAI::Model* pModel) { return createBlock(pModel, 5., 0., 0., 10., 10., 10.); }}, {L"Cylinder", [](OdDAI::Model* pModel) { return createRightCircularCylinder(pModel, 5., 0., 0., 10., 5., 0., 0., 1.); }}, {L"Sphere", [](OdDAI::Model* pModel) { return createSphere(pModel, 5., 5., 5., 5.); }}, {L"Torus", [](OdDAI::Model* pModel) { return createTorus(pModel, 10., 2., 5., 0., 0., 0., 0., 1.); }}, {L"Extrusion", [](OdDAI::Model* pModel) { OdDAIObjectId lineId = createEllipArc(pModel, 5., 0., 0., 7., 5.); return createSolidOfLinearExtrusion(pModel, lineId, 10., 0., 0., 1.); }}, {L"Revolution", [](OdDAI::Model* pModel) { OdDAIObjectId arcId = createCircularArc(pModel, 0., 5., 0., 10., 0., 0., 0.); return createSolidOfRevolution(pModel, 0, arcId, Oda2PI, 5., 0., 0., 1., 0., 0.); }}, {L"Wedge", [](OdDAI::Model* pModel) { return createRightAngularWedge(pModel, 5., 0., 0., 10., 10., 10., 5., 1., 0., 0., 0., 0., 1.); }}, {L"ConeFrustum", [](OdDAI::Model* pModel) { return createRightCircularConeFrustum(pModel, 5., 0., 0., 10., 5., 2., 0., 0., 1.); }}, {L"Ellipsoid", [](OdDAI::Model* pModel) { return createEllipsoid(pModel, 5., 3., 2., 5., 0., 0., 1., 0., 0., 0., 0., 1.); }} }; const std::map Tutorial_06::booleanOperationMap = { {L"Union", Iges::kboolean_op_code_union}, {L"Intersection", Iges::kboolean_op_code_intersection}, {L"Difference", Iges::kboolean_op_code_difference} }; int Tutorial_06::run(MyServices& svcs, const std::vector& argv, std::ostream& resultStream) { int parseResult = BaseIgesTutorial::run(svcs, argv, resultStream); if (parseResult != 0) { return parseResult; } if (m_outputFileName.isEmpty()) { odPrintConsoleString(OD_T("Error: Output file not specified.\n")); return 1; } if (m_operand1Type.isEmpty() || m_operand2Type.isEmpty() || m_booleanOperation.isEmpty()) { odPrintConsoleString(OD_T("Error: Missing operand types or boolean operation. \n")); odPrintConsoleString(OD_T("Please specify -operand1 , -operand2 , and -operation .\n")); return 1; } // Validate operand types for the first operand auto it1 = csgObjectFactories.find(m_operand1Type); if (it1 == csgObjectFactories.end()) { odPrintConsoleString(OD_T("Error: Unknown operand1 type: %ls\n"), m_operand1Type.c_str()); return 1; } // Validate operand types for the second operand (using its specific factory map) auto it2 = csgSecondOperandFactories.find(m_operand2Type); if (it2 == csgSecondOperandFactories.end()) { odPrintConsoleString(OD_T("Error: Unknown operand2 type: %ls\n"), m_operand2Type.c_str()); return 1; } // Validate boolean operation auto itOp = booleanOperationMap.find(m_booleanOperation); if (itOp == booleanOperationMap.end()) { odPrintConsoleString(OD_T("Error: Unknown boolean operation: %ls\n"), m_booleanOperation.c_str()); odPrintConsoleString(OD_T("Available operations: Union, Intersection, Difference\n")); return 1; } IgesFilePtr igesFile = svcs.createDatabase(); OdDAI::ModelPtr model = igesFile->getModel(sdaiRW); // Create the two CSG operands, ensuring the second is offset OdDAIObjectId csg1_id = it1->second(model); OdDAIObjectId csg2_id = it2->second(model); // Create views_visible instance Iges::views_visiblePtr viewsVisible = Iges::views_visible::createObject(model); viewsVisible->setlabel(""); viewsVisible->setsubscript(0); OdDAI::ListOfOdDAIObjectId& dev = viewsVisible->dev(); dev.createEmpty(); OdDAI::ListOfOdDAIObjectId& de = viewsVisible->de(); de.createEmpty(); // Create the Boolean Tree OdDAIObjectId booleanResultId = createBooleanTree(model, itOp->second, csg1_id, csg2_id); de.putByIndex(0, booleanResultId); // Write the IGES file writeIgesFile(igesFile, m_outputFileName, booleanResultId); odPrintConsoleString(OD_T("Generated: %ls\n"), m_outputFileName.c_str()); odPrintConsoleString(OD_T("\nSuccessfully generated one IGES file with CSG boolean operation.\n")); return eOk; }