How to create a Parametric Feature Tree

Introduction

Parametric Feature is powerful way of creating complex geometry associatively. Various parametric features can be combined to form a chain; often called as a feature tree.

What does the example demonstrate?

'Parametric Feature Tree Tool' app demonstrates how to create a complex chain of Parametric Features programmatically.

To run the Example

  1. Load the 'Parametric Feature Tree Tool' application using either
    1. Key-In: mdl load examplesolids Or
    2. Utilities -> MDL Applications -> Browse ...select: exampleSolids.ma
  2. Launch 'EXAMPLE PARAMETRICFEATURETREE' key-in.
  3. Observe 'Parametric Feature Tree Tool' dialog
  4. Select an element e.g. a line and enter a data point.
  5. The app creates a parametric feature tree.
  6. The program output in the form of cylindrical shaped geometry is displayed.
  7. Checking the properties of the geometry will show the feature tree as shown below.
  8. Select a geometry and observe Parametric Feature Tree in Properties Pane.
  9. In the properties dialog each feature in the tree is called as feature node.
  10. In this example the tree consists of following feature nodes:
    1. Ellipse (used as profile to create Extrude)
    2. Extrude
    3. Blend
    4. Ellipse (used as a tool for Cut)
    5. Cut

Code Walkthrough

Please refer MstnExamples/Elements/exampleSolids/exampleParametricFeatureTree.cpp file for comprehensive steps.

Following is important excerpts:

Step 1: Create Ellipse (a primary profile for a extrude feature node)

    DgnModelRefP modelRef = NULL;
    if (modelName)
        modelRef = getModel(modelName);
    else
        modelRef = ISessionMgr::GetActiveDgnModelP();

    if (modelRef)
        {
            if (SUCCESS == EllipseHandler::CreateEllipseElement(eeh, NULL, center, major, minor, 0, modelRef->Is3d(), *modelRef))
                eeh.AdToModel();
            else
                BeAssert(false);
        }

Step 2: Create Extrude

// Step 2.a: First always cook the setting of a parametric feature. In this case -  ExtrudeSettings
    CurveVectorPtr          curveVector;
    if (SUCCESS != SmartFeatureUtil::GetCurveVector(curveVector, ellipseEh, true))
        return ERROR;   

    DPlane3d                plane;
    SmartFeatureUtil::GetCurveVectorPlane(plane, *curveVector);  

    ExtrudeSettings settings(hitPt, false, false, NULL, 1.0, 1.0, 0.0, false, 0, 0.0, ev, *curveVector); 

    // Step 2.b: Create a extrude feature node by using the feature settings. 
    SmartFeatureNodePtr extrudeFeatureNode = FeatureCreate::CreateExtrudeFeature(settings);
    if(!extrudeFeatureNode.IsValid())
        return ERROR;      

    // Step 2.c: Write extrude feature node over an element and the element into the dgn file.
    T_ChildElementToControlFlagsMap childElementToControlFlagsMap;
    T_ControlFlagsVector controlFlags(3, false); // {visible, temporary, profile} - Irrevalent for Smart Feature with single child.
    childElementToControlFlagsMap[ellipseEh.GetElementRef()] = controlFlags;

    EditElementHandle extrudeEeh;
    if (SUCCESS != SmartFeatureElement::CreateAndWriteSmartFeatureElement(extrudeEeh, ellipseEh, ellipseEh.GetDgnModelP(), *extrudeFeatureNode, childElementToControlFlagsMap, false /*mergeParametrics*/))
        return ERROR;

Step 3: Create Blend

// Step 3.a: Retrieve solid body of extrude feature node.      
    if (!extrudeEeh.IsValid())      
        return ERROR;

    ISolidKernelEntityPtr body;
    if (SUCCESS != extrudeFeatureNode->GetBody(body, extrudeEeh, true, true, true, false))
        return ERROR;

    // Step 3.b: Get edges of extruded solid body.
    bvector<ISubEntityPtr> edges;
    SolidUtil::GetBodyEdges(&edges, *body);

    // Step 3.c: Since the Blend creation API don't require any specific settings to be cooked, create a Blend feature node directly.
    double blendRadius = 5000.00;
    SmartFeatureNodePtr blendFeatureNode;
    if (SUCCESS != FeatureCreate::CreateBlendFeature(blendFeatureNode, edges, blendRadius, true /*propogateSmooth*/))
        return ERROR;

    if (!blendFeatureNode.IsValid())
        return ERROR;

    childElementToControlFlagsMap.clear();
    childElementToControlFlagsMap[extrudeEeh.GetElementRef()] = controlFlags;

    // Step 3.d: Write a blend feature node over an element and eventually into the dgn file.
    EditElementHandle blendEeh;
    if (SUCCESS != SmartFeatureElement::CreateAndWriteSmartFeatureElement(blendEeh, extrudeEeh, extrudeEeh.GetDgnModelP(), *blendFeatureNode, childElementToControlFlagsMap, false /*mergeParametrics*/))
        return ERROR;

Step 4: Create Ellipse (a tool element for a Cut)

    DgnModelRefP modelRef = NULL;
    if (modelName)
        modelRef = getModel(modelName);
    else
        modelRef = ISessionMgr::GetActiveDgnModelP();

    if (modelRef)
        {
            if (SUCCESS == EllipseHandler::CreateEllipseElement(eeh, NULL, center, major, minor, 0, modelRef->Is3d(), *modelRef))
                eeh.AdToModel();
            else
                BeAssert(false);
        }

Step 5: Create Cut

    // Step a: Create a cut feature node
    SmartFeatureNodePtr cutFeatureNode;
    SolidUtil::Modify::CutDepthMode depthMode = SolidUtil::Modify::CutDepthMode::All;
    SolidUtil::Modify::CutDirectionMode directionMode = SolidUtil::Modify::CutDirectionMode::Forward;
    bool outsideProfile = true; // Cut outside the profile  
    double depth = 0.0; // Irrelevant - due to depthMode = All
    DVec3d defaultNormal = DVec3d::From(0.0, 0.0, 1.0); // Along Z-axis
    if (SUCCESS != FeatureCreate::CreateCutFeature(cutFeatureNode, depthMode, directionMode, outsideProfile, depth, &defaultNormal))
        return ERROR;

    if (!cutFeatureNode.IsValid())
        return ERROR;

    // Step b: Write a cut feature node on element handle and write element handle in dgn file. 
    childElementToControlFlagsMap.clear();
    childElementToControlFlagsMap[blendEeh.GetElementRef()] = controlFlags;  // {visible = false, temporary = false, profile = false}
                           
    controlFlags.clear();
    controlFlags.push_back(false);
    controlFlags.push_back(false);
    controlFlags.push_back(true);
    childElementToControlFlagsMap[ellipseCutProfileEh.GetElementRef()] = controlFlags; // {visible = false, temporary = false, profile = true}

    EditElementHandle cutEeh;
    if (SUCCESS != SmartFeatureElement::CreateAndWriteSmartFeatureElement(cutEeh, blendEeh, blendEeh.GetDgnModelP(), *blendFeatureNode, childElementToControlFlagsMap, true /*mergeParametrics*/))
        return ERROR;

Anonymous