Tcl for Creo – Feature Creation Revisited

The following examples demonstrate how to build, create, modify and redefine Creo features directly from Tcl, including the placement of a UDF – all without compiling a single line of code.

Note: The feature tree structure and its underlying element types are defined by PTC. p-Shell provides a Tcl interface to build, manipulate and maintain a representation of this structure. Before feature creation, the feature tree is temporary. After creation, it is re-parsed from the actual Creo feature tree; when redefining a feature, its feature ID remains unchanged. Selection objects are restored by their original names, provided those names have not been changed.

For clarity and readability, the example scripts omit error handling and focus on the functionality being demonstrated.

More information you will find here: Tcl for Creo

Examples

  1. Datum Point – Build, create, reuse, modify and redefine a Creo feature tree.
  2. First Feature – Demonstrate the general mechanism for creating the first sketched feature.
  3. UDF Round – Place a predefined Creo UDF with just four lines of Tcl code.

Tcl Object Commands

p-Shell provides Tcl representations for several Creo object types. The following three are particularly useful when working with model geometry and assembly structures:

  1. Component Path: Identifies where the component is located in the assembly.
  2. Model Item: What is it?
  3. Selection Object: Combines both to identify exactly what is selected.

All three types are available as Tcl object commands.

Datum Point

Let’s start with a datum point created at the intersection of an axis and a planar surface. The following example demonstrates how to build and manipulate a Creo feature tree directly from Tcl.

# This example demonstrates how to:
#
#   - Build a feature tree for a Creo datum point.
#   - Create a feature using user-defined selections.
#   - Reuse the same feature tree with different selections.
#   - Modify individual feature tree elements.
#   - Redefine an existing feature using the modified tree.
#

# Create a feature tree object for a datum point named 'PSPNT1'.

ps_ftree ftObjDtmPnt

# on rerun, destroy the tree, '.' is the tree root 
# if we don't destroy we need to configure
# each item path .1 .2 ....
ftObjDtmPnt delete .

# Get a unique name by increment an counter
set n [incr ::PntCounter]

# Selection objects are created automatically when referenced
# in the feature tree, if they do not already exist.

# In this example, two selection objects are used:
#   ::PS::FTREE::SEL.Axis
#   ::PS::FTREE::SEL.Surface
#
# They will hold the references to the axis and surface
# used to define the datum point.
#
# Build the feature tree.
# The following structure was extracted from an existing
# Creo datum point of the same type using the 'get' subcommand.

ftObjDtmPnt insert .1 -type FEATURE_TYPE -map_integer DATUM_POINT
ftObjDtmPnt insert .2 -type DPOINT_TYPE -integer -1
ftObjDtmPnt insert .3 -type STD_FEATURE_NAME -wstring PSPNT
ftObjDtmPnt insert .4 -type DPOINT_POINTS_ARRAY -array
ftObjDtmPnt insert .4.1 -type DPOINT_POINT -compound
ftObjDtmPnt insert .4.1.1 -type DPOINT_POINT_NAME -wstring  PSPNT$n
ftObjDtmPnt insert .4.1.2 -type DPOINT_PLA_CONSTRAINTS -array
ftObjDtmPnt insert .4.1.2.1 -type DPOINT_PLA_CONSTRAINT -compound
ftObjDtmPnt insert .4.1.2.1.1 -type DPOINT_PLA_CONSTR_REF -selection ::PS::FTREE::SEL.Axis
ftObjDtmPnt insert .4.1.2.1.2 -type DPOINT_PLA_CONSTR_TYPE -integer 0
ftObjDtmPnt insert .4.1.2.1.3 -type DPOINT_PLA_CONSTR_VAL -double 0.0
ftObjDtmPnt insert .4.1.2.2 -type DPOINT_PLA_CONSTRAINT -compound
ftObjDtmPnt insert .4.1.2.2.1 -type DPOINT_PLA_CONSTR_REF -selection ::PS::FTREE::SEL.Surface
ftObjDtmPnt insert .4.1.2.2.2 -type DPOINT_PLA_CONSTR_TYPE -integer 0
ftObjDtmPnt insert .4.1.2.2.3 -type DPOINT_PLA_CONSTR_VAL -double 0.0
ftObjDtmPnt insert .4.1.3 -type DPOINT_DIM_CONSTRAINTS -array

#
# Ask the user to select the axis and the surface.
#
# Alternatively, you can configure the selection objects
# programmatically and provide the references directly.
#
# For simplicity, we let the user make the selections here.
#
# Displays a message in the status line at the bottom of 
# the Creo window, informing the user what is expected.
# The message can optionally be accompanied by an icon 
# indicating Warning, Error, or Critical.

ps_mess “Please select an axis.”
::PS::FTREE::SEL.Axis select axis

ps_mess “Please select a planar surface.”
::PS::FTREE::SEL.Surface select surface

# Create the datum point.
# After creation, pShell reparses the feature tree.
ftObjDtmPnt create

# Retrieve the ID of the newly created feature.
set FID [ftObjDtmPnt cget -id]

#
# The same feature tree can be reused to create another datum point.
# However, each feature requires its own selection objects,
# since they are associated with different feature IDs.
#
# Due to the reparse, we need to retrieve the selection objects
# again from the updated tree.
#
# The tree structure and element order remain unchanged:
# .4.1.2.1.1 holds the axis reference.
# .4.1.2.2.1 holds the surface reference.

# Keep the same axis, but select a different surface.
# Retrieve the surface selection object and change its contents.
set CurSelSurface [ftObjDtmPnt itemcget .4.1.2.2.1 -value]

ps_mess “Please select a planar surface.”
$CurSelSurface select surface

# Create another datum point using the updated selection.
ftObjDtmPnt create

# refresh the window
ps_wind

#
# You can also modify individual elements of the feature tree.
# Here we change the axis reference to a different selection object.
#

ftObjDtmPnt itemconfigure .4.1.2.1.1 -selection ::PS::FTREE::SEL.NewAxis

# Ask the user to select the new axis.

ps_mess “Please select an axis.”
::PS::FTREE::SEL.NewAxis select axis

#
# Redefine the existing datum point using the new axis.
# The same feature tree object is reused.
#

ftObjDtmPnt redefine

# refresh the window
ps_wind

First Feature

The main procedure handles feature creation, while the sketch definition is separated into its own procedure, supported by a helper procedure.

#
# Warning:
#   This script deletes all existing
#   features in the current model first!
#
# Objective:
#   Create the first extrusion in a Creo model
#   

proc Create_First_Feature {} {

##
# Shortcut to the Feature Tree Command
##
        set f        ftree

##
# Get the current model (a Part is assumed)
##
        set model [ps_model current]

##
# empty model - this is our FIRST_FEAT
##
        ps_feat delete -model $model [ps_feat list -model $model]

##
# Convert the model to a modelitem
# Note: The miObj is created on the fly
# You don't need to call 
# ps_modelitem miObj before
##
        ps_model to_modelitem  -model $model -- miObj


##
# Create a selection object and assign the modelitem.
# The selection object refers to miObj rather than keeping
# an independent copy.
# If miObj changes, selObj is reconfigured and updated
# the next time it is used.
##
        ps_sel selObj -modelitem miObj

##
# Create a feature treeObj
# Just for the demo, delete and configure again
# Note: Calling the command twice in row will not raise an error
# ps_ftree TestFTree
# ps_ftree TestFTree
# but calling now
# ps_ftree selObj
# will raise an error, because selObj is a Selection command
# Here ps_obj is introduced, if you want to make sure to have a fresh tree
##

        if [ps_obj exists $f] {
                ps_obj delete $f
        }

        ps_ftree $f 

##
#        Set the model you want to work on
#        rather to use the currently active one
##
        $f config -selection        selObj

##
# Available creation options:
# NONE, DEFINE_MISS_ELEMS, INCOMPLETE_FEAT,
# FIX_MODEL_IF_FAIL and DO_NOT_DISPLAY.
# Specify the desired options as a list.
# The default is NONE.
##
        $f config -options        INCOMPLETE

##
# Note: 
# Before you start, create the feature you want
# and get the tree from the existing feature id
# ps_ftree ftree -id 233
# ftree get -> will now return the tree data
#
# Insert feature incomplete data
# The nodes names are integer values
# On creation you can use your own naming
# like for the widgets and toplevel
# but on 'visit' or 'get', only numerical are used
# and returned
# 
##
        $f insert .1        -type         FEATURE_TYPE                 -map                FIRST_FEAT
        $f insert .2        -type         FEATURE_FORM                 -map                EXTRUDE   
        $f insert .3                 -type STD_EXT_DEPTH                        -compound 
        $f insert .3.1                 -type EXT_DEPTH_FROM                 -compound 
        $f insert .3.1.1         -type EXT_DEPTH_FROM_TYPE         -integer        262144
        $f insert .3.1.2         -type EXT_DEPTH_FROM_VALUE         -double                120.0
        $f insert .3.2                 -type EXT_DEPTH_TO                        -compound 
        $f insert .3.2.1         -type EXT_DEPTH_TO_TYPE                -integer         0
        $f insert .3.2.2        -type EXT_DEPTH_TO_VALUE        -double                0.0

##
# Create the incomplete feature
# The nodes above may the minimum required
# 
# After this call, the underlying tree is updated
# and a handle to the 2D section for sketching is available
# See the complete tree at the bottom of this script documentation 
# After this call,
##
        set success [$f create]

##
# Retrieve the sketcher section handle from the updated
# feature tree.
# This demonstrates how to get a node/element value
# from an existing feature tree.
##
        set HaveSketch [Get_Root_Children_Value_From $f sketcher sketcherObj ]

        if { $HaveSketch == 0 } {     
                return 0
        }
##
# Now add items to the sketch
##
        Create_Section $sketcherObj
        
# Configure the creation options
        $f config -options        none
        
# Create the feature
# by the redefined tree
# Now after having the full feature tree
# and a Sketch with geometry
# create the first feature
# the workflow is similar to the one
# if you do that in Creo by yourself

        $f redefine

# refit the window, rather a simple refresh
#
        ps_wind        refit        $model

        set fid [$f cget -id]
        return $fid
}


##
# Helper to retrieve a value from a root-level child.
# The proc will not find sub level items/elements
# Walk through all root children and search for the
# specified type.
# Return 1 on success or 0 if the type is not found.
# Store the retrieved value in the variable passed
# by name.
#
# ftree the feature tree
# GetType the requested node type
# from cbr_value, a variable passed by ((Call by) reference
##
proc Get_Root_Children_Value_From {ftree GetType cbr_value} {
        
        # use the root node '.'
        set RootChildren [$ftree child .]
        
        # The type values are all in upper
        set GETTYPE [string toupper $GetType]
        
        # now search for the given upper string
        foreach child $RootChildren {         
                set ITEMTYPE [$ftree itemcget $child -type]
                if { $ITEMTYPE eq $GETTYPE } {
                        upvar $cbr_value Value 
                        set Value [$ftree itemcget $child -value]
                        return 1
                }
        }
        
        return 0
}

##
# Create the sketch entities:
# five lines and an arc.
#
# Both ps_line and ps_arc support the -is_construction option.
# ps_arc also supports the -type option.
# The type can be either ARC or CIRCLE.
#
# For a CIRCLE, the start and end points are ignored.
# For an ARC, the -is_construction flag is ignored.
##
proc Create_Section {sketchObj} {
        set width        300
        set height        250
        set bite_r         20
        set bite_h         30

        set bhmbr        [expr $bite_h - $bite_r]
        set bhpbr        [expr $bite_h + $bite_r]

        for {set i 1 } {$i < 6} {incr i} {
                # reuse, no delete here
                ps_line l$i
        }

        l1 2d_values        [list        0.0                0.0                $width        0.0        ]
        l2 2d_values        [list        $width        0.0                $width        $height        ]
        l3 2d_values        [list        $width        $height        0.0                $height        ]
        l4 2d_values        [list        0.0                $height        0.0                $bhpbr        ]
        l5 2d_values        [list        0.0                $bhmbr        0.0                0.0        ]

        # create the arc 
        ps_arc        a1        -xo        0.0        -yo        $bite_h                -radius        $bite_r -start_angle 270 -end_angle 90

        # Add this to the 2D Sketch
        foreach item [list l1 l2 l3 l4 l5 a1] {
                $sketchObj        create [string tolower [$item cget -type]] $item
        }
 
        $sketchObj        auto_dim
        $sketchObj        regen
        
        return
}

  The complete feature tree in Tcl after creation was called:
.1 -type FEATURE_TYPE -map_integer FIRST_FEAT
.2 -type FEATURE_FORM -map_integer EXTRUDE
.3 -type STD_FEATURE_NAME -wstring EXTRUDE_1
.4 -type EXT_SURF_CUT_SOLID_TYPE -integer 917
.5 -type REMOVE_MATERIAL -integer 0
.6 -type BODY -compound 
.6.1 -type TARGET_BODY -integer 2
.6.2 -type TOOL_BODIES -selection ::PS::FTREE::SEL.4
.7 -type IS_SMT_CUT -integer 0
.8 -type SMT_CUT_NORMAL_DIR -integer 0
.9 -type SKETCHER -pointer ::PS::FTREE::SKETCH.4
.10 -type STD_SECTION -compound 
.10.1 -type STD_SEC_METHOD -integer 0
.10.2 -type SEC_USE_SKETCH -selection {}
.10.3 -type STD_SEC_SELECT -compound 
.10.3.1 -type STD_CURVE_COLLECTION_APPL -selection {}
.10.3.2 -type SURF_CHAIN_CMPND -compound 
.10.3.2.1 -type SURF_CHAIN_METHOD -integer 0
.10.3.2.2 -type SURF_CHAIN_REF_SURFS -array 
.10.3.2.2.1 -type SURF_CHAIN_SURF -compound 
.10.3.2.2.1.1 -type SURF_CHAIN_REF -selection {}
.10.3.3 -type STD_SEC_BLN_VERTS -selection {}
.10.4 -type STD_SEC_SETUP_PLANE -compound 
.10.4.1 -type STD_SEC_PLANE -selection {}
.10.4.2 -type STD_SEC_PLANE_VIEW_DIR -integer 0
.10.4.3 -type STD_SEC_PLANE_ORIENT_DIR -integer 0
.10.4.4 -type STD_SEC_PLANE_ORIENT_REF -selection {}
.10.5 -type SKETCHER  
.11 -type FEAT_FORM_IS_THIN -integer 0
.12 -type STD_MATRLSIDE -integer 0
.13 -type THICKNESS -double 0.0
.14 -type SRF_END_ATTRIBUTES -integer 0
.15 -type TRIM_QUILT -selection {}
.16 -type TRIM_QLT_SIDE -integer 0
.17 -type STD_DIRECTION -integer 0
.18 -type STD_EXT_DEPTH -compound 
.18.1 -type EXT_DEPTH_FROM -compound 
.18.1.1 -type EXT_DEPTH_FROM_TYPE -integer 0
.18.1.2 -type EXT_DEPTH_FROM_VALUE -double 120.0
.18.1.3 -type EXT_DEPTH_FROM_REF -selection {}
.18.1.4 -type EXT_DEPTH_FROM_REF_TRF -integer 0
.18.1.5 -type EXT_DEPTH_FROM_REF_TRF_VAL -double 0.0
.18.2 -type EXT_DEPTH_TO -compound 
.18.2.1 -type EXT_DEPTH_TO_TYPE -integer 0
.18.2.2 -type EXT_DEPTH_TO_VALUE -double 0.0
.18.2.3 -type EXT_DEPTH_TO_REF -selection {}
.18.2.4 -type EXT_DEPTH_TO_REF_TRF -integer 0
.18.2.5 -type EXT_DEPTH_TO_REF_TRF_VAL -double 0.0
.19 -type INT_PARTS  
.20 -type PATTERN  
.21 -type STD_SMT_THICKNESS -double 0.0
.22 -type STD_SMT_SWAP_DRV_SIDE -integer 0
.23 -type SMT_WALL_SHARPS_TO_BENDS -integer 0
.24 -type SMT_PUNCH_AXIS_PNT -integer 0
.25 -type SMT_FILLETS -compound 
.25.1 -type SMT_FILLETS_SIDE -integer 0
.25.2 -type SMT_FILLETS_VALUE -double 0.0
.26 -type SMT_DEV_LEN_CALCULATION -compound 
.26.1 -type SMT_DEV_LEN_SOURCE -integer 0
.26.2 -type SMT_DEV_LEN_Y_FACTOR -compound 
.26.2.1 -type SMT_DEV_LEN_Y_FACTOR_TYPE -integer 0
.26.2.2 -type SMT_DEV_LEN_Y_FACTOR_VALUE -double 0.0
.26.3 -type SMT_DEV_LEN_BEND_TABLE -integer 0
.27 -type SMT_PUNCH_TOOL_DATA -compound 
.27.1 -type SMT_PUNCH_TOOL_ATTR -integer 0
.27.2 -type SMT_PUNCH_TOOL_NAME -wstring 
.28 -type SMT_MERGE_DATA -compound 
.28.1 -type SMT_MERGE_AUTO -integer 0
.28.2 -type SMT_MERGE_KEEP_LINES -integer 0
.28.3 -type SMT_MERGE_KEEP_BEND_EDGES -integer 0
.29 -type EXT_COMP_DRFT_ANG -compound 
.29.1 -type EXT_DRFT_ANG -integer -1
.29.2 -type EXT_DRFT_ANG_VAL -double 0.0
.30 -type FEAT_THIN -compound 
.30.1 -type FEAT_THIN_STRT -compound 
.30.1.1 -type FEAT_THIN_STRT_OPT -integer 0
.30.1.2 -type FEAT_THIN_STRT_REF -selection {}
.30.2 -type FEAT_THIN_END -compound 
.30.2.1 -type FEAT_THIN_END_OPT -integer 0
.30.2.2 -type FEAT_THIN_END_REF -selection {}



  A similar example (just a box) written in C
ProError CreoFirstFeatureCreate()

{

  ProErrorlist            errors;
  ProMdl                  model;
  ProModelitem            model_item;
  ProSelection            model_sel;
  ProFeature              feature;
  ProFeatureCreateOptions *opts = 0;
  ProElempath             path;
  ProElempathItem         path_items[2];
  ProSection              section;
  ProAsmcomppath          comp_path;
  ProAsmcomppath          *p_comp_path = NULL;
  ProValue                value;
  ProValue                new_value;
  ProElement sketch_element; 
  ProElement created_elemtree; 
  ProElement pro_e_feature_tree;
  ProElement pro_e_feature_type;
  ProElement pro_e_feature_form;
  ProElement pro_e_feat_form_is_thin;
  ProElement pro_e_thickness;
  ProElement pro_e_std_ext_depth;
  ProElement pro_e_ext_depth_from;
  ProElement pro_e_ext_depth_from_type;
  ProElement pro_e_ext_depth_from_value;
  ProElement pro_e_ext_depth_to;
  ProElement pro_e_ext_depth_to_type;
  ProElement pro_e_ext_depth_to_value;
  ProElement pro_e_sketcher;
  ProError status;
  ProValueData    value_data;
  ProSelection * p_select;

  int             n_select;
  ProStringToWstring ( message_file, "utilities.txt" ); 

  log_file = PTApplsUnicodeFopen ( "ug_sketched_curve.log", "w" ); 

  /*---------------------------------------------------------------*\

    Populating root element PRO_E_FEATURE_TREE 

  \*---------------------------------------------------------------*/

    status = ProElementAlloc ( PRO_E_FEATURE_TREE, &pro_e_feature_tree ); 

  

  /*---------------------------------------------------------------*\

    Populating element PRO_E_FEATURE_TYPE 

  \*---------------------------------------------------------------*/

 

  status = ProElementAlloc ( PRO_E_FEATURE_TYPE, &pro_e_feature_type );

  status = ProElementIntegerSet(pro_e_feature_type,PRO_FEAT_FIRST_FEAT);

  status = ProElemtreeElementAdd ( pro_e_feature_tree, NULL, pro_e_feature_type );

  /*---------------------------------------------------------------*\

    Populating element PRO_E_FEATURE_FORM 

  \*---------------------------------------------------------------*/

  status = ProElementAlloc ( PRO_E_FEATURE_FORM, &pro_e_feature_form );

  status = ProElementIntegerSet(pro_e_feature_form,PRO_EXTRUDE);

  status = ProElemtreeElementAdd ( pro_e_feature_tree, NULL, pro_e_feature_form );

  /*---------------------------------------------------------------*\

    Populating  compound element PRO_E_STD_EXT_DEPTH

  \*---------------------------------------------------------------*/

  status = ProElementAlloc ( PRO_E_STD_EXT_DEPTH, &pro_e_std_ext_depth );

  status = ProElemtreeElementAdd ( pro_e_feature_tree, NULL, pro_e_std_ext_depth  );

  /*---------------------------------------------------------------*\

    Populating  element PRO_E_STD_EXT_DEPTH

                  -> PRO_E_EXT_DEPTH_FROM

  \*---------------------------------------------------------------*/

  status = ProElementAlloc ( PRO_E_EXT_DEPTH_FROM, &pro_e_ext_depth_from );

  status = ProElemtreeElementAdd ( pro_e_std_ext_depth, NULL, pro_e_ext_depth_from  );

   /*---------------------------------------------------------------*\

    Populating  element PRO_E_STD_EXT_DEPTH

                        -> PRO_E_EXT_DEPTH_FROM

                           -> PRO_E_EXT_DEPTH_FROM_TYPE

  \*---------------------------------------------------------------*/

  status = ProElementAlloc ( PRO_E_EXT_DEPTH_FROM_TYPE, &pro_e_ext_depth_from_type );

  status = ProElementIntegerSet(pro_e_ext_depth_from_type,PRO_EXT_DEPTH_FROM_BLIND);

  status = ProElemtreeElementAdd ( pro_e_ext_depth_from, NULL, pro_e_ext_depth_from_type );

   /*---------------------------------------------------------------*\

    Populating  element PRO_E_STD_EXT_DEPTH

                  -> PRO_E_EXT_DEPTH_FROM

                     -> PRO_E_EXT_DEPTH_FROM_VALUE

  \*---------------------------------------------------------------*/

  status = ProElementAlloc ( PRO_E_EXT_DEPTH_FROM_VALUE, &pro_e_ext_depth_from_value );

  status = ProElementDecimalsSet( pro_e_ext_depth_from_value,4 );

  status = ProElementDoubleSet(pro_e_ext_depth_from_value,120.000000);

  status = ProElemtreeElementAdd ( pro_e_ext_depth_from, NULL, pro_e_ext_depth_from_value );
 

  /*---------------------------------------------------------------*\

    Populating  element PRO_E_STD_EXT_DEPTH

                        -> PRO_E_EXT_DEPTH_TO  

  \*---------------------------------------------------------------*/

  status = ProElementAlloc ( PRO_E_EXT_DEPTH_TO, &pro_e_ext_depth_to );

  status = ProElemtreeElementAdd ( pro_e_std_ext_depth, NULL, pro_e_ext_depth_to );


   /*---------------------------------------------------------------*\

    Populating  element PRO_E_STD_EXT_DEPTH

                        -> PRO_E_EXT_DEPTH_TO

                           -> PRO_E_EXT_DEPTH_TO_TYPE

  \*---------------------------------------------------------------*/

  status = ProElementAlloc ( PRO_E_EXT_DEPTH_TO_TYPE, &pro_e_ext_depth_to_type );

  status = ProElementIntegerSet(pro_e_ext_depth_to_type,PRO_EXT_DEPTH_TO_BLIND);

  status = ProElemtreeElementAdd ( pro_e_ext_depth_to, NULL, pro_e_ext_depth_to_type );


   /*---------------------------------------------------------------*\

    Populating  element PRO_E_STD_EXT_DEPTH

                        -> PRO_E_EXT_DEPTH_TO

                           -> PRO_E_EXT_DEPTH_TO_VALUE

  \*---------------------------------------------------------------*/

  status = ProElementAlloc ( PRO_E_EXT_DEPTH_TO_VALUE, &pro_e_ext_depth_to_value );

  status = ProElementDecimalsSet( pro_e_ext_depth_to_value,4 );

  status = ProElementDoubleSet(pro_e_ext_depth_to_value,0.0);

  status = ProElemtreeElementAdd ( pro_e_ext_depth_to, NULL, pro_e_ext_depth_to_value );

  /*---------------------------------------------------------------*\

    Creating incomplete feature in the current model.

  \*---------------------------------------------------------------*/

  status = ProMdlCurrentGet (&model);

  if ( status != PRO_TK_NO_ERROR ) return ( status );

  status = ProMdlToModelitem( model, &model_item ); 

  status = ProSelectionAlloc (p_comp_path, &model_item,

                     &model_sel);


  status = ProArrayAlloc(1,sizeof(ProFeatureCreateOptions),   1, (ProArray*)&opts);


  opts[0]= PRO_FEAT_CR_INCOMPLETE_FEAT;

  status = ProFeatureWithoptionsCreate (model_sel, pro_e_feature_tree,   opts, PRO_REGEN_NO_FLAGS, &feature, &errors);

  status = ProArrayFree((ProArray*)&opts);

  /* Using the element tree from created feature */ 

  status = ProFeatureElemtreeExtract (&feature, NULL, PRO_FEAT_EXTRACT_NO_OPTS, &created_elemtree);

  /*---------------------------------------------------------------*\

    Getting the initialized section element from the database.

  \*---------------------------------------------------------------*/

  /* path to PRO_E_SKETCHER element */ 

  path_items[0].type = PRO_ELEM_PATH_ITEM_TYPE_ID;

  path_items[0].path_item.elem_id = PRO_E_SKETCHER;

  status = ProElempathAlloc (&path);

  status = ProElempathDataSet (path, path_items, 1);

  status = ProElemtreeElementGet ( created_elemtree, path, &sketch_element);

  status = ProElementSpecialvalueGet(sketch_element, NULL, (ProAppData *) &section);

  double section_eps;

  status = ProSectionEpsilonGet (section,&section_eps);

/*---------------------------------------------------------------*\

   Creating a 3-D section 

\*---------------------------------------------------------------*/

  status = UserSectionFirstFeatureBuild (( ProSection * )(&section) );

/*---------------------------------------------------------------*\

   Allocating and assigning new ProValue to sketcher element

      :: Wildfire requirement

\*---------------------------------------------------------------*/

  status = ProElementSpecialvalueSet(sketch_element, (ProAppData) section);

  ProElempathFree (&path);

/*---------------------------------------------------------------*\

   Redefining the feature to make it complete.

\*---------------------------------------------------------------*/

  status = ProSelectionAsmcomppathGet (model_sel, &comp_path);

  status = ProArrayAlloc(1,sizeof(ProFeatureCreateOptions),  1, (ProArray*)&opts);


  opts[0]= PRO_FEAT_CR_DEFINE_MISS_ELEMS;

  status = ProFeatureWithoptionsRedefine (&comp_path, &feature, created_elemtree,    opts, PRO_REGEN_NO_FLAGS, &errors);

  status = ProArrayFree((ProArray*)&opts);

/*---------------------------------------------------------------*\

    Free up the allocated memory.

\*---------------------------------------------------------------*/

  status = ProFeatureElemtreeFree (&feature, created_elemtree ); 

  status = ProElementFree (&pro_e_feature_tree ); 

  return (status);

}

 

ProError UserSectionFirstFeatureBuild ( ProSection * section_here )

{

  Pro2dLinedef line; 
  ProError status; 
  int line_id[4]; 
  ProName section_name; 
  ProWSecerror section_errors1; 
  ProWSecerror section_errors2; 
  ProWSecerror section_errors3; 
  int n_sec; 
  ProMsg error_message;  
  char error_message_s[100];
  int i, error_id; 

   status = ProSecerrorAlloc ( &section_errors1 ); 
  status = ProSecerrorAlloc ( &section_errors2 ); 
  status = ProSecerrorAlloc ( &section_errors3 ); 
  status = ProSection2DAlloc ( section_here ); 
  ProTKPrintf("The status for ProSection2DAlloc is = %d\n", status );

  line.type = PRO_2D_LINE;
  line.end1[0] = 0;
  line.end1[1] = 0;
  line.end2[0] = 100; 
  line.end2[1] = 0; 

  status = ProSectionEntityAdd ( *section_here, (Pro2dEntdef*)&line, &line_id[0] ) ;

  line.type = PRO_2D_LINE;
  line.end1[0] = 100;
  line.end1[1] = 0;
  line.end2[0] = 100; 
  line.end2[1] = 100; 


  status = ProSectionEntityAdd ( *section_here, (Pro2dEntdef*)&line, &line_id[1] ) ;

  line.type = PRO_2D_LINE;
  line.end1[0] = 100;
  line.end1[1] = 100;
  line.end2[0] = 0; 
  line.end2[1] = 100; 

  status = ProSectionEntityAdd ( *section_here, (Pro2dEntdef*)&line, &line_id[2] ) ;


  line.type = PRO_2D_LINE;
  line.end1[0] = 0;
  line.end1[1] = 100;
  line.end2[0] = 0; 
  line.end2[1] = 0; 
 

  status = ProSectionEntityAdd ( *section_here, (Pro2dEntdef*)&line, &line_id[3] ) ;
  status = ProSectionEpsilonSet( *section_here, 0.1 );
  status = ProSectionAutodim ( *section_here, &section_errors1 ); 
  if ( status != PRO_TK_NO_ERROR )

    {
      status = ProSecerrorCount ( &section_errors1, &n_sec ); 
      ProTKPrintf("The status for ProSecerrorCount is = %d\n", status );
      ProTKPrintf("Number of errors in the ProSectionAutodim = %d \n",n_sec ); 
      for ( i = 0; i < n_sec; i++ )
      {
        status = ProSecerrorMsgGet (section_errors1, i, error_message);
        ProTKPrintf("The status for ProSecerrorMsgGet is = %d\n", status );
        ProWstringToString (error_message_s, error_message);
        status = ProSecerrorItemGet ( section_errors1, i, &error_id);
        ProTKPrintf("The status for ProSecerrorMsgGet is = %d\n", status );
        ProTKPrintf(" %s : Problem ID : %d \n", error_message_s, error_id );
      }
    }
 
  status = ProSectionRegenerate ( *section_here, &section_errors3 ); 
  if ( status != PRO_TK_NO_ERROR )
    {
      status = ProSecerrorCount ( &section_errors3, &n_sec ); 
      ProTKPrintf("The status for ProSecerrorCount is = %d\n", status );
      ProTKPrintf("Number of errors in ProSectionRegenerate = %d \n",n_sec ); 
    }

  return ( status ); 

}

UDF Round

Note: The UDF definition file simple_round.gph used in this example must be available in the current working environment. This depends on your current config.pro settings. Alternatively, you can configure the file path directly in the udfObj command.

# Simple round on the current solid model using a UDF.
# The round uses a fixed radius.
#
# UDF definition:
#   Prompt    = 'edge'
#   Selection = EDGE (one reference)
#

# Create the UDF object and specify the UDF name.
ps_udf udfObj -name simple_round

# Assign the selection object to the UDF prompt 'edge'.
udfObj add_selection edge selObj

# Ask the user to select an edge.
selObj sel edge

# Create and apply the UDF.
udfObj create

Creo Configuration Options

Creo configuration options, such as pro_group_dir, can be queried and modified at runtime using ps_info:

# Retrieve the current value of a configuration option.
set value [ps_info config OptionName]

# Set or change a configuration option.
ps_info config OptionName NewValue

Changes are applied directly to the running Creo session.

Object Configuration: configure and cget

Model items and other pShell objects provide the configure and cget commands to manage and retrieve their properties. configure displays available options and allows writable properties to be modified. cget retrieves the current value of a specific property. Read-only properties are marked with RO in the configure output and can only be retrieved using cget.

Model Items

A model item is a complex variable representing an item within a Creo model. It references a Creo model, an item type (such as a feature, edge, surface, axis, part, etc.) and the corresponding item ID.

Model items can be used to retrieve information, extract properties and modify the referenced item where supported by the Creo Toolkit.

Like a Tk widget, a model item provides a set of commands to configure the object and retrieve its properties using configure and cget.

A model item can also be linked to Selection objects, allowing changes to be propagated automatically.

Example: Hiding a Creo Feature (if Creo Supports it)

# Create a model item referencing feature ID 238
# in the Creo model box.prt.

ps_modelitem miPlane -model box.prt -type Feature -id 238

# Hide the referenced feature.
# The effect depends on the type of model item:
# A hole feature will remain visible, whereas
# a datum feature will be hidden.

miPlane hide
# For example, hiding a hole feature has no effect, 
# whereas a datum feature will be hidden.

Component Path

A component path object identifies where a component is located within a Creo assembly structure and at which level of the assembly hierarchy. It contains the sequence of component feature IDs from the top-level assembly down to the target component. It can be used to identify a specific component occurrence, even when the same part is used multiple times within an assembly.

In short: A component path tells you where a solid component is located.

Accessing Components within the Path

The cpObj provides two commands to retrieve information about individual levels of the assembly hierarchy:

  • model_in_level – Returns the model name at the specified level.
  • compid_in_level – Returns the component ID at the specified level.

The component path is represented as a list of integer values. You can use integer values to address any level within the component path. Additionally, the Tcl-style indices end and end-1 are supported for addressing levels relative to the end of the path.

  • 0 – The root (top-level) assembly.
  • end – The selected component (the target model).
  • end-1 – The parent assembly.

For example:

# Get the name of the selected model (bottom level).
set modelName [cpObj model_in_level end]

# Get the component ID of the selected component.
set compId [cpObj compid_in_level end]

# Get the name of the parent assembly of ‘modelName’
set parentName [cpObj model_in_level end-1]

Selection Objects

A selection object is a complex variable representing a Creo ProSelection. It can be created with ps_sel and then used wherever a selection is required within pShell. A selection object can be configured interactively or programmatically and reused throughout the application. Within the feature tree, the selection objects are identified by name, so keeping their original names allows pShell to restore the references after reparsing.

For example:

# Create two selection objects.
ps_sel selAxis
ps_sel selSurface

# Let the user define their contents.
selAxis select axis
selSurface select surface

# Extract the model item data from each selection object.
# The data is copied, no link is established.
# The same model item object will be reused.
selAxis modelitem miObj
set axisId [miObj cget -id]

selSurface modelitem miObj
set surfaceId [miObj cget -id]

Selection Object – Extracting and Linking Data

Extract the model item data from the selection object into a model item object.

# Extract
selObj modelitem miObj

The model item selection data is copied to the named model item object. The two objects remain independent.

Alternatively, a model item and a component path can be linked directly to a selection object:

# Link
selObj configure -modelitem miObj -comppath cpObj

Once linked, the objects automatically keep each other updated:

  1. When the selection changes, the linked model item and component path are updated.
  2. When the model item or component path changes, the selection object is updated accordingly on next use.
# Create a selection object linked to a model item.
# The model item is created automatically if it does not exist.

ps_sel selObj -modelitem miObj

# The model item is now linked to the selection object.
# Changes to miObj will automatically update selObj.

# Select an axis belonging to the model item.
selObj select axis

# Get the updated information from the linked model item
# Retrieve the ID of the selected axis. 
set axisId [miObj cget -id]

The 150% model approach

Instead of constructing every feature programmatically, create a deliberately over-complete model in Creo. The model contains all the potential features and geometric alternatives required by the application. The important idea is that the model contains the design intent, while the application controls which parts of that intent are active.

Through TOOLKIT, however, every operation requires explicit programming, including geometry creation, references, feature definitions, regeneration, error handling and model-state management. The difficulty is not simply creating geometry. It is maintaining the complete parametric design intent.

Consider a simple rectangular block.

  • Initially, it has six faces, twelve edges and eight vertices.
  • To create a blind hole, the application must identify the intended face.
  • It must establish the sketch coordinate system and orientation.
  • It must define the placement and dimensions.
  • It must create the cut feature.

Now consider a second operation on the opposite face. Which face is the intended one? The application must identify it reliably, not just during initial construction, but after subsequent modifications and regeneration.

Possible identification criteria include:

  • Surface orientation and normal vectors.
  • Surface position.
  • Surface area.
  • Geometric type.
  • Adjacency and neighbouring geometry.

None of these automatically expresses the designer's intent.

Drawings introduce another major complication

This is an aspect that is easy to overlook. A Creo drawing is not simply a visual representation of the model. It is another structured engineering document with its own information and dependencies. When a drawing is created, additional information must be established.

My recommendation

Direct feature creation through TOOLKIT is technically possible, but technical feasibility is not the same as a sensible development architecture.

Don't use Creo/TOOLKIT to reinvent Creo's modeling capabilities. Use Creo to define the modeling intent and Creo/TOOLKIT to control its execution.