Tcl for Creo

Scripting, Customization and Automation using Tcl (Language) scripts in Creo

p-Shell is a Creo Application which runs synchronous or a-synchronous with Creo 2.0 - 4.0 as a Binary Tcl Extensions, and enables you to access Creo Files and their Database via Tcl commands within a running Tcl/Tk environment.

  • For a synchronous application you will setup a menu once during Creo start, and specify a file to be sourced if the user picked this menu button.
  • In a-synchronous mode you start Creo, and after the connection is established you can call any p-Shell command or whatever may required for your application.

This pages shows some of many p-Shell built-In commands. This allows scripting in Creo for administrative or automation jobs and application development.

p-Shell Environment is available for Tcl/Tk 8.5 and/or 8.6

A console in synchronous mode is available to test interactive p-Shell commands before using it in a program, or to execute admin tasks. In a-synchronous mode, start wish, load the dll, connect to Creo (see further below, how to do) and start typing the commands, and of course by sourcing Tcl files.

You can develop your application without restarting Creo over and over, source your code again, and simply validate your changes! Or evaluate commands in a shell before using.

More info: Tcl4Creo (at) gmail (dot) com

Code Samples and more Info follows here

  Access to Parameter and a sample output

This section shows how to work with parameter/attributes in Creo using the p-Shell command 'ps_param'

Sample: Get the list of all parameter in a Creo Model. Simple output or export of all parameter within the current Creo CAD model to a csv file.

# write all parameter from a given model # into a csv file with the name $model.creo.param.csv
proc GetParamToCSV {model} {
# csv delimeter ',' or ';' ? set del ";"
# create the file set fp [open $model.creo.param.csv w]
# write the header puts $fp [join [list Name Type Value] $del]
# sorted param names output, get all parameter from the given model foreach paramObj [lsort -dictionary [ps_param list -model $model] ] { set nam [$paramObj cget -name ] set val [$paramObj cget -value ] set typ [$paramObj cget -type ] puts $fp [join [list $nam $typ $val] $del] }
# close and return close $fp return
# call the function with the active/current model GetParamToCSV [ps_model current] 

Get parameter for each Part model in session

foreach model [ps_glob *.prt] { GetParamToCSV $model }

Sample: Create new parameter (or modify if exists) and change/set the value

# Create a parameter
set paramCmd [ps_param set MY_Param String {Hello World} ] #
# Configure the value
# $paramCmd configure -value "Hello" -designate Yes -description "Don't change me manually" #
#Create two string parameter at the first feature with the ID 1 # ps_modelitem miObj -model box.prt -type Feature -id 1 set paramObjs [ps_param set -at_item miObj -- [list MY_Param1 MY_Param2] String {Unknown} ]
  Parameter objects usage

Show some commands and usage. Assume the parameter name is 'IDENT' and the final value should be "A-123-K-009", enable export to Windchill.

Note: Range and restricted values are also implemented.

# Set a parameter by name, type and value
# Make sure we have a parameter which is a STRING
# Check if exists
# if ![ps_param exists IDENT] { #
# Okay create it
# set paramCmd [ps_param set IDENT String "This is a Identnumber, please change me." ] } else { #
# Paramter exists. Is parameter a STRING type ?
# If locked create an error
# set paramCmd [ps_param list IDENT] if [$paramCmd islocked] { error "Error: Parameter IDENT is locked" } if ![string equal [$paramCmd cget -type] STRING ] {
# Wrong type
# Get val and create a string type
# set val [$paramCmd cget -value] #
# Delete the param
# $paramCmd delete #
# Create as a STRING type with old value
# set paramCmd [ps_param set IDENT String $val ] } } #
# Change to the final value and enable with designate the export to Windchill
# $paramCmd configure -value "A-123-K-009" -designate Yes -description "This Parameter will hold the Article Number" 
  Tcl Attribute Viewer for Creo/Attributes in a multi column listbox

The first image on top is from Creo, the bottom one is done by the script below.

# SimpleAttrViewr --
# Most of this code is from tree demonstration script # AttrDataInsert contains the code to get model parameter
# and fill the data into the tree widget
# proc AttrInit {} { set cols {name type valu desi desc} set names {Name Type Value Designate Description} set tree [AttrBuild .mclist $cols $names] set model [ps_model cur] AttrDataInsert $tree $cols $model } proc AttrDataInsert {tree cols model} { set rows [list] foreach paramObj [lsort -dictionary [ps_param list -model $model] ] { set name [$paramObj cget -name ] set valu [$paramObj cget -value ] set type [$paramObj cget -type ] set desi [$paramObj cget -desi ] set desc [$paramObj cget -descr ] lappend rows [list $name $type $valu $desi $desc] } # Instead of 0/1 display True/False set DES(1) True set DES(0) False foreach row $rows { foreach $cols $row {} $tree insert {} end -values [list $name [string totitle $type] $valu $DES($desi) $desc] } } #
# Code for sort removed
# to make it easier to read
proc AttrBuild {tl cols names} { set w $tl catch {destroy $w} toplevel $w wm title $w "p-Shell Multi Colums Parameter List" wm iconname $w "mclist" ttk::frame $w.container ttk::treeview $w.tree -columns $cols -show headings -yscroll "$w.vsb set" -xscroll "$w.hsb set" ttk::scrollbar $w.vsb -orient vertical -command "$w.tree yview" ttk::scrollbar $w.hsb -orient horizontal -command "$w.tree xview" pack $w.container -fill both -expand 1 grid $w.tree $w.vsb -in $w.container -sticky nsew grid $w.hsb -in $w.container -sticky nsew grid column $w.container 0 -weight 1 grid row $w.container 0 -weight 1
# Configure the header foreach col $cols name $names { $w.tree heading $col -text $name -image noArrow -anchor w $w.tree column $col -width 40 }
# return the tree widget return $w.tree
# Call the Init proc

Note: Working with dimensions is similar, a dimObj will contain more info (Tolerance, Tolerance Label, owning FeatId, the value,...) which can be extracted with the 'cget' option.

  Command Syntax - Syntax, access other models, '-help'

Each p-Shell command follows the same rule, here a short explanation.

The task: For the drawing drawing.drw set the format std_a3.frm at sheet number 1.

ps_draw set_format -drawing drawing.drw -- std_a3.frm 1
  1. the main command ps_draw
  2. the command switch set_format
  3. Command options for this switch -drawing drawing.drw
  4. -- mark the end of options
  5. The arguments for the command switch, the name of the format, and at which sheet number std_a3.frm 1
 Output of 'ps_draw -help' list_models ?Pattern? set_format FormatName ?SheetNumber? ?FormatSheetNumber? format_get matrix SheetNumber matrixObj overlay_view SheetNumber views scale SheetNumber ?Value? add_model delete_model regen_draft display_status View Option ?Value? replace sourceModel targetModel ?unrepresent_ok? add_view positionPoint orientationMatrix Scale SheetNumber ?exploded? add_project_view positionPoint ParentView ?exploded? create_from_template templateName newName ?Display? notes current ?NewCurrentModel? srep_add_asm SREP_Name getsize setsize Size ?xval yval? detail_option_get Option ?NewValue? format_is_shown hide_format show_format -help'

If your active model is the requested drawing.

ps_draw set_format std_a3.frm 1

If the drawing is not active but in session.

ps_draw set_format -drawing drawing.drw -- std_a3.frm 1

You can omit --

ps_draw set_format -drawing drawing.drw std_a3.frm 1

Note: Each command has a '-help' option.

  Simple button which saves the current model

Short example to create a "Save Button" (file save) for the current active model in Creo. The label contains the name of the active model.

ps_model current will return the name of the active model, e.g. K-AB-123.PRT, or an empty string if no model is active.

ps_file save will save the active model to disk, or ps_file save box.drw will save the drawing 'box.drw' to disk.

pack [button .mdlsave -text "Save [ps_model current]" -command {ps_file save} ]
  Create a new menu entry in Creo - Callback Menu

Provide a Callback menu in Creo.

Based on the installation, there is a 'program' folder, each folder may provide a Tcl Callback program if you place a 'pshell_init.tcl' file within this folder. By this, a simple copy of a folder into your program structure will enable the Tcl Scripts to run in Creo.

Sample 'pshell_init.tcl' file, argv0 is the path to the init file. The 'program' folder are parsed once, recursively on Creo Start. The command may supply additional arguments.

proc PShell_Init {dir} { ps_auto_menu add -root {My Attributes} \ -text {Model Attributes} \ -command [list $dir/MyAttributes.tcl] } PShell_Init [file dirname $argv0] 

If the user select now the menu "Tools->My Attributes->Model Attributes" in Creo the file '$dir/MyAttributes.tcl' in the same dir of the 'pshell_init.tcl' file gets sourced an executed. Note: All required files for Creo (menu files) will be created automatically on run time. To end the Tcl program call 'exit', which will only end the running Tcl program.

  Creo scripted feature creation - Create and redefine a datum point

Create a feature (tree) in Creo. Assume you would like to create a datum point as an intersection of a plane with one axis.

# First get the feature tree by creating the feature by yourself.
# Assume Feature ID 56 is a Datum Point created as an intersection of a plane with an axis ps_ftree ftObj -id 56 ftObj get

This is the output of the 'get' command

.1 -type FEATURE_TYPE -map_integer DATUM_POINT
.2 -type DPOINT_TYPE -integer -1
.3 -type STD_FEATURE_NAME -wstring APNT12
.4 -type DPOINT_POINTS_ARRAY -array .4.1 -type DPOINT_POINT -compound .4.1.1 -type DPOINT_POINT_NAME -wstring APNT12
.4.1.2 -type DPOINT_PLA_CONSTRAINTS -array . -type DPOINT_PLA_CONSTRAINT -compound . -type DPOINT_PLA_CONSTR_REF -selection ::PS::FTREE::SEL.1
. -type DPOINT_PLA_CONSTR_TYPE -integer 0
. -type DPOINT_PLA_CONSTR_VAL -double 0.0
. -type DPOINT_PLA_CONSTRAINT -compound . -type DPOINT_PLA_CONSTR_REF -selection ::PS::FTREE::SEL.2
. -type DPOINT_PLA_CONSTR_TYPE -integer 0
. -type DPOINT_PLA_CONSTR_VAL -double 0.0
.4.1.3 -type DPOINT_DIM_CONSTRAINTS -array 

Now create your own

# Create the Object, give the feature and the point a name 'PSPNT1' ps_ftree ftObjDtmPnt #
# if a selection is inserted and the selection does not exists
# the selObj will be created
# here in this sample ::PS::FTREE::SEL.Axis and ::PS::FTREE::SEL.Surface
# 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 PSPNT1
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 PSPNT1
ftObjDtmPnt insert .4.1.2 -type DPOINT_PLA_CONSTRAINTS -array ftObjDtmPnt insert . -type DPOINT_PLA_CONSTRAINT -compound ftObjDtmPnt insert . -type DPOINT_PLA_CONSTR_REF -selection ::PS::FTREE::SEL.Axis
ftObjDtmPnt insert . -type DPOINT_PLA_CONSTR_TYPE -integer 0
ftObjDtmPnt insert . -type DPOINT_PLA_CONSTR_VAL -double 0.0
ftObjDtmPnt insert . -type DPOINT_PLA_CONSTRAINT -compound ftObjDtmPnt insert . -type DPOINT_PLA_CONSTR_REF -selection ::PS::FTREE::SEL.Surface
ftObjDtmPnt insert . -type DPOINT_PLA_CONSTR_TYPE -integer 0
ftObjDtmPnt insert . -type DPOINT_PLA_CONSTR_VAL -double 0.0
ftObjDtmPnt insert .4.1.3 -type DPOINT_DIM_CONSTRAINTS -array #
# Ask the user for the axis and the surface
# you can also manually configure the selection obj to specify the axis and the surface
# Here to make it easy ask the user ::PS::FTREE::SEL.Axis select axis
::PS::FTREE::SEL.Surface select surface # Now create the datum point
ftObjDtmPnt create # get the feature ID
set FID [ftObjDtmPnt cget -id] # now change the selected plane by asking again
::PS::FTREE::SEL.Surface select surface # Now create the datum point by using the new plane
# with the same feature tree
ftObjDtmPnt create # you can also configure all elements
# here we change the selection ftObjDtmPnt itemconfigure . -selection ::PS::FTREE::SEL.NewAxis # now get the new axis
:PS::FTREE::SEL.NewAxis select axis # Now redefine the datum point by using the new axis
# with the same feature tree
ftObjDtmPnt redefine 

Mass properties

  Mass properties - Traverse an assembly and export mass properties

Get all mass properties from an active assembly and all sub components, traverse (walk through) and use the first CSYS or the system default, to calculate the mass prop data.

proc PS_Mass_Prop_Assy {} { # Get current model set CurModel [ps_model cur] set ext [ps_model ext -model $CurModel] if {![string equal $ext ASM]} { Debug "Expect an assembly 'ASM' but got $CurModel '$EXT'" return } PS_Mass_From_Model $CurModel PS_Mass_Traverse $CurModel } proc PS_Mass_Traverse {model} { Debug "Traverse Model $model" # Get Component ID's set CompIDs [ps_visit type -model $model component] foreach CompID $CompIDs { # get component name set CompName [ps_assy component_name -model $model $CompID] Debug "Assembly $model Component ID $CompID CompName $CompName" # get the extension set ext [ps_model ext -model $CompName] switch $ext { PRT { # # proceed each subtype ? # SKELETONS may not have a weight # Skip everything if not a SOLID # set SUBTYPE [ps_model subtype -model $CompName] switch $SUBTYPE { SOLID { } default { Debug "Skip Model $CompName Subtype $SUBTYPE for mass prop calc" red continue } } # Get Mass Prop PS_Mass_From_Model $CompName } ASM { # Get Mass Prop PS_Mass_From_Model $CompName # rekursive call PS_Mass_Traverse $CompName } default { Debug "Unknow extension '$ext' in assy '$model' found" return } } } } proc PS_Mass_From_Model {m} { Debug "PS_Mass_From_Part '$m'" set CSysIDs [ps_visit csys -model $m] Debug "CSysIDs Geom Ids '$CSysIDs'" set num [llength $CSysIDs] if {$num == 0} { Debug "Calc MProp based on default, no CSYS found" set dict1 [ps_solid basic_mass_prop -model $m ] set dict2 [ps_solid math_mass_prop -model $m ] } else { Debug "ps_geom names -model $m CSYS $CSysIDs" set names [ps_geom names -model $m CSYS $CSysIDs] Debug "names $names" set use [lindex $names 0] Debug "For calculation take the first one '$use' " set dict1 [ps_solid basic_mass_prop -model $m -csys $use] set dict2 [ps_solid math_mass_prop -model $m -csys $use] } # or all indicies in one arry array set basic $dict1 array set extend $dict2 # output or join and write to a csv file foreach item [lsort [array names basic]] { Debug "basic $item $basic($item)" } # output or join and write to a csv file foreach item [lsort [array names extend]] { Debug "extend $item $extend($item)" } } # Call Main Function PS_Mass_Prop_Assy

Debug Output (cut only for toplevl assembly)

Debug : proc PS_Mass_From_Model PS_Mass_From_Part 'ENGINE.ASM' CSysIDs Geom Ids '8' ps_geom names -model ENGINE.ASM CSYS 8 names ASM_DEF_CSYS For calculation take the first one 'ASM_DEF_CSYS' basic CENTER_OF_GRAVITY.X 0.013103156721395044 basic CENTER_OF_GRAVITY.Y 18.48877898819197 basic CENTER_OF_GRAVITY.Z 25.652370056147102 basic DENSITY 1000.0000000000003 basic MASS 41422192.0786966 basic SURFACE_AREA 30802.63214818563 basic UNITSYSTEMTYPE MASS_LEN_TIME basic UNITTYPE_LENGTH mm basic UNITTYPE_MASS kg basic VOLUME 41422.192078696586 extend INERTIA_MATRIX.IXX_IXY_IXZ.X 2974291992.942244 extend INERTIA_MATRIX.IXX_IXY_IXZ.Y -13421519.761119707 extend INERTIA_MATRIX.IXX_IXY_IXZ.Z 31272945.442605354 extend INERTIA_MATRIX.IYX_IYY_IYZ.X -13421519.761119707 extend INERTIA_MATRIX.IYX_IYY_IYZ.Y 31640536282.290863 extend INERTIA_MATRIX.IYX_IYY_IYZ.Z 13752835676.919683 extend INERTIA_MATRIX.IZX_IZY_IZZ.X 31272945.442605354 extend INERTIA_MATRIX.IZX_IZY_IZZ.Y 13752835676.919683 extend INERTIA_MATRIX.IZX_IZY_IZZ.Z 37105163761.98315 extend INERTIA_TENSOR.IXX_IXY_IXZ.X 68745700044.27402 extend INERTIA_TENSOR.IXX_IXY_IXZ.Y 13421519.761119707 extend INERTIA_TENSOR.IXX_IXY_IXZ.Z -31272945.442605354 extend INERTIA_TENSOR.IYX_IYY_IYZ.X 13421519.761119707 extend INERTIA_TENSOR.IYX_IYY_IYZ.Y 40079455754.92539 extend INERTIA_TENSOR.IYX_IYY_IYZ.Z -13752835676.919683 extend INERTIA_TENSOR.IZX_IZY_IZZ.X -31272945.442605354 extend INERTIA_TENSOR.IZX_IZY_IZZ.Y -13752835676.919683 extend INERTIA_TENSOR.IZX_IZY_IZZ.Z 34614828275.23311 extend PRINCIPAL_AXES.1.X -0.001631475347182119 extend PRINCIPAL_AXES.1.Y 0.8785253011946432 extend PRINCIPAL_AXES.1.Z -0.47769303265701174 extend PRINCIPAL_AXES.2.X 0.001100349292419445 extend PRINCIPAL_AXES.2.Y 0.47769495633622155 extend PRINCIPAL_AXES.2.Z 0.8785250809865192 extend PRINCIPAL_AXES.3.X 0.9999980637579385 extend PRINCIPAL_AXES.3.Y 0.0009076628210328389 extend PRINCIPAL_AXES.3.Z -0.00174603223827789 extend PRINCIPAL_MOMENTS.X 9617533725.350153 extend PRINCIPAL_MOMENTS.Y 23659502930.638294 extend PRINCIPAL_MOMENTS.Z 27328570062.012695 

Welding Component

  Welding - Find Component Reference for Welding Feature

In the next example, you have an active Drawing, and you want to update parameter in a Repeat Region. The attached drawing model must be an assembly (not checked).

The feature Parameter for Welding Feature should contain 2 parameter, Article_1 and Article_2. Assumption: This 2 Parameter are the contact/welded components given by the feature parents of the identified weld.

If you do a weld, and you have welded sheet1.prt and sheet2.prt by one weld, the value of the weld feature parameter 'Article_1' will be set to sheet1.prt or sheet2.prt based on the order of the selection. This two parameter are include in the repeat region.

proc Run_Script {} {
# We need a modelitem for the feature parameter catch {ps_modelitem miObj} # Get the attached Model set CurAssy [ps_draw current] # Get the list of all Weld_fillet feature ID's set Welds [ps_visit type -model $CurAssy WELD_FILLET] # now proceed for each welding foreach Weld $Welds { set ParentIDs [ps_feat parents -model $CurAssy $Weld] Debug "Weld $Weld Parents $ParentIDs" set refIDs [list] foreach ParentID $ParentIDs { set type [ps_feat type -model $CurAssy -- $ParentID] if {[string equal $type COMPONENT]} { lappend refIDs $ParentID } else { Debug "Expect a Component got $type for Parent ID $ParentID" } } # ignore in this sample if we don't have 2 Parents which are Components if { [llength $refIDs] != 2} { Debug "For FeatID $Weld expect two component references got '$refIDs' from Parent IDs '$ParentIDs'" continue } set Comp1 [lindex $refIDs 0] set Comp2 [lindex $refIDs 1] # get the component name from the FeatID set CompName1 [ps_assy component_name -model $CurAssy $Comp1] set CompName2 [ps_assy component_name -model $CurAssy $Comp2] # configure modelitem to point to the Weld Feature ID Debug "Modelitem conf -type feat -model $CurAssy -id $Weld" miObj conf -type feat -model $CurAssy -id $Weld # # Create or update the Parameter 'Article_1' and 'Article_2' # Instead of Component_Name. Ext write only the Component Name Update_Parameter miObj Article_1 [file root $CompName1] Update_Parameter miObj Article_2 [file root $CompName2] } } #
# This procedure will create or update a feature Parameter
proc Update_Parameter {item name value} { if {![ps_param exist -at $item $name]} { # Ok, not existing, create it Debug "Created param $item $name '$value'" ps_param set -at $item $name String $value } else { # ok, exists get the handle and configure the value set Param [ps_param list -at $item $name] Debug "Modify $name '$value'" $Param config -value $value }
} Run_Script

Sheet Metal

  Sheet Metal - Basic info like surface area, perimeter

Simple Sheet Metal Stuff, get the surface area for one side from an active sheet metal part.

'ps_visit surf' will return all surface ID's for the given model ps_geom smt_surf_type' will return a list of Type and ID, like 'GREEN 123 WHITE 2333 SIDE 3434', the input is a list of Surface ID's

# for this sample I use the 'switch' statement, not string ..., ignoring the other types WHITE ...

proc PS_SMT_Surface {} { set data [ps_geom smt_surf_type [ps_visit surf]] set vals [list] foreach {COL ID} $data { switch $COL { GREEN { set AREA [ps_geom area $ID] lappend vals $AREA } } } set total [expr [join $vals + ]] return $total } #
# Get the surface area from the green side from the current active model
set Area [PS_SMT_Surface]
  Drawing Code snippets - Deal with sheet and drawing models

Simple Drawing Stuff, add a sheet and set a format. Use the same format as for sheet number 1. Assume drawing.drw is in memory but not active.

# How many sheets we have
set num [ps_sheet number -drawing drawing.drw]
if {$num == 1 } { # get format name from sheet number one set myfrm [ps_sheet format -drawing drawing.drw -- 1] # add a new sheet ps_sheet add -drawing drawing.drw # set the format at sheet 2 (default format sheet number is 1) ps_draw set_format -drawing drawing.drw -- $myfrm 2 # activate sheet number 2 ps_sheet set 2
  Family Table - Access data in a family table, and delete or add new instances

Assume you would like to add a column to our current model, the column should contain the Parameter Material, add an instance and assign Aluminum.

# Default is the current Model
# else you can configure the command # with the option "-model ModelName"
# if you try to manage the same model
# twice, an error will be raised
# Get the handle to our family table ps_famtab myFT
# Insert the column
myFT insert Parameter Material
# Insert a new Instance
mfFT add PS12345
# Set the Value for the new instance
mfFT set PS12345 Material Aluminum 

Some sample task if you want to extract or set Family Table Data.

Sample family Table Data
Name F126 d9 Material
PS78047 Y 14.800 Steel
0007564187 * * *
0007564185 N 15.000 Copper
0007564186 * 20.000 Aluminium # Get the ObjectCommand
ps_famtab ft # Get all names
ft names
0007564187 0007564185 0007564186 # get header info
ft header
ft column_ids
-> F126 D9 MATERIAL # get data by column
ft get_column_data MATERIAL
-> * Copper Aluminium
# or
ft get_column_data d9
-> * 15.0 20.0 # get the whole list
ft get_col -> {* N *} {* 15.0 20.0} {* Copper Aluminium} # count the number of instances
ft nins
-> 3 # get the number of rows
ft ncol
-> 3 # get all data instance by instance
ft get_instance_data
-> {* * *} {N 15.0 Copper} {* 20.0 Aluminium} # get data for one instance
ft get_instance_data 0007564186
-> * 20.0 Aluminium # set by instance
ft set_instance_data 0007564186 [list Y 22.2 Gold] # delete an instance
ft delete 0007564187 # remove a columns
ft remove_column d9 # delete the whole table
ft erase 
  Asynchronous mode - connect, start Creo, connect to Windchill

In Asynchronous mode you start Creo or connect to an existing session. After this you can drive Creo without having a callback in a Creo Menu.

# Simple asynchrounes Creo Session
# to load a Creo Drawing and export an DXF file
# Execute in Tcl as a callback or just in plain Tcl
# #
# Setup to callback functions
# Invoked after connection is establish
proc pShell_Init {} {puts "Connected"}
# Invoked after connection is closed
proc pShell_Exit {} { puts "Session closed"} #
# In Tcl get the DLL
package req pshell_asyn #
# Configure and Start the Creo Session
ps_session ::PS::SessionCmd \ -exit pShell_Exit \ -init pShell_Init \ -timeout 20 \ -text C:/p-Shell/programs/text \ -pro_comm_msg [file native "C:/Creo 2/Common Files/M200/x86e_win64/ob/pro_comm_msg.exe"] #
# Start Creo # after connect 'pShell_Init' is called
::PS:SessionCmd start [file native "C:/Creo 2/Parametric/bin/creo2.bat"] #
# Note: This script continues if Creo is running and connection is established #
# Make sure that all Datums are not displayed
# Load a config file wich will turn on/off what we want
# ps_import config c:/Release/ #
# Open the Drawing from your Project Directory
ps_file open C:/ProjectData/CreoFiles/P12KU88/box.drw #
# Get the referenced model
# No error check here (None or more than one)
set refMdl [ps_draw list -drawing box.drw] #
# Make sure not to display a certain layer, turn off a layer where we have only curves
# No error check here (Layer exists, current status) ps_layer set -model $refMdl -- ALL_CURVES Blank #
# Update the title block to display the current day (This is Based on the used Format)
# assume parameter DRW_RELASE_DATE is new or exists as a string #
ps_param set DRW_RELEASE_DATE String [clock format [clock seconds] -format "%m/%d/%y"] #
# Display the Drawing in a Window
ps_wind set box.drw #
# Create the DXF file
ps_export dxf -model box.drw -- box.dxf #
# Save the drawing with the updated parameter
ps_file save box.drw #
# Stop the session
# This will eval 'pShell_Exit' and delete all p-Shell commands
::PS:SessionCmd stop

Asyn & Windchill (Sample)

Another example to export Creo Objects to a local folder from Windchill

# Setup to callback functions
# Invoked after connection is establish
proc pShell_Init {} {puts "Connected"}
# Invoked after connection is closed
proc pShell_Exit {} { puts "Session closed"} #
# In Tcl get the DLL
package req pshell_asyn #
# Configure and Start the Creo Session
ps_session ::PS::SessionCmd \ -exit pShell_Exit \ -init pShell_Init \ -timeout 20 \ -text C:/p-Shell/programs/text \ -pro_comm_msg [file native "C:/Creo 2/Common Files/M200/x86e_win64/ob/pro_comm_msg.exe"] #
# Start Creo # after connect 'pShell_Init' is called
::PS:SessionCmd start [file native "C:/Creo 2/Parametric/bin/creo2.bat"] #
# Create the Server Command
ps_server serverObj #
# Configure the Server Command
serverObj configure -serverurl http://MyWindchill/windchill -alias MyConnectionName #
# Prepare Username and Password for http://MyWindchill/windchill
serverObj login MyUserName MyPassword #
# Register an existing Workspace 'MyWorkspace'
serverObj register MyWorkspace #
# Add both assemblies into the Workspace MyWorkspace
# After add to workspace the objects are not "Checked Out"
# serverObj multiobjcheckout [list assy1.asm assy2.asm] false #
# Open both assemblies in Creo
# ps_file open assy1.asm
ps_file open assy2.asm #
# Save both assemblies in an existing folder named 'c:/temp/export/assyX'
ps_file backup assy1.asm c:/temp/export/assy1
ps_file backup assy2.asm c:/temp/export/assy2 # If you CheckOut models
# and next modified in Session or # saved to an active Workspace
# use:
# serverObj checkin ?Modelname?
# to checkin the data to Windchill
# eg: serverObj checkin assy1.asm
# if Modelname is not given, # the whole Workspace will be checked in
# Stop the session
::PS:SessionCmd stop


  Assembly - information and assembling components

Command options for ps_assy are:

 component_name FeatID is_bulk_item FeatID type FeatID matrix_get comppathObj Matrix matrix_set comppathObj Matrix explode ?NewState? interchange IDs ReplaceModel create NAME.EXT Unplaced ?Template? dynamic_position ?NewState? assemble Component Matrix modelItemObjReturn setconstraints ModelItem Constraints ?CompPath? getconstraints ModelItem Constraints numofconstraints ModelItem -help 

Assemble a Component

Example: Assembly by CSYS

If you assemble by Coordinate system, you can use the name of the CSYS to identify the model item. Like in Creo you have to specify the assembly reference and the component reference.

For placing Components (single model or another assembly) in one assembly you need to specify the target assembly, the component/assembly to assembly and an initial matrix.

The return value on placing a component is a model item, which contains the component info, for feature id and type.

We assembly the component 'comp.prt' by using the coordinate system with the name 'CS0' into the assembly 'assy.asm' by using the coordinate system with the name 'ACS0'.

You must supply the same info, as if you would do this in Creo manually.

Basically a selection object contains a component path and a model item reference, this must be supplied by your calls. Component Path is not required in the following example.

You need to supply a component path if you would like to use a reference in the target assembly, which is for example a csys of an already assembled component.

Note: A component can be assembled multiple times, the component path will uniquely identify the model item in an assembly.

# Vars for the models to be used
# model handle
# set ASSY assy.asm
set PART comp.prt # Create two selection objects
# one for the assembly reference # one for the component reference ps_sel AssySelObj
ps_sel CompSelObj # create two modelitem Obj
# one for the assembly
# one for the component ps_modelitem AssyMiObj
ps_modelitem CompMiObj # A csys for sure has a name
# Note: The Feature ID of the CSYS is not the ID, which is used later
# The Geometric ID will be used
# set data, fill csys geometric id, type and owner.
# one for the assembly
# one for the component # This two calls will setup the model items with valid values
# if the given name and type is valid AssyMiObj byname $ASSY csys ACS0
CompMiObj byname $PART csys CS0 #
# Configure selection object's
# to use the model item information
# one for the assembly
# one for the component AssySelObj config -modelitem AssyMiObj
CompSelObj config -modelitem CompMiObj #
# create the constraint Object
ps_asmconstraint constraintObj #
# setup the type by 'csys'
constraintObj config -constrainttype CSYS
# set the info, same as manually done in Creo after selecting the references
# Could be done in one statement as well
constraintObj config -asmselection AssySelObj -asmdatumside none
constraintObj config -compselection CompSelObj -compdatumside NONE #
# Create a default matrix for initial position
ps_matrix matrixObj #
# Assemble the component first without any constraints
# You only have to take care that # 'PlacedMiObj' does not exists as a command with another type.
# You can create it upfront as well, same for the Matrix Object
# ps_assy assemble -model $ASSY -- $PART matrixObj PlacedMiObj # Final call to set the constraints
# We don't need to specify a component path in this sample # Only 2 (not 3) args given to the function
# 'PlacedMiObj' is the result from assembling without constraints
# this uniquely identifies the component to configure # 'list' is used to keep in mind that you may need to specify more the one constraint
# If you assembe by datum planes you need to supply normally 3 constraints #
# If this fail, you may want to delete the placed component with ps_feat delete ?ID? # The feature id you get with: 'PlacedMiObj cget -id'
# Configure the placed component to make if fully parametric
ps_assy setconstraints PlacedMiObj [list asmconObj] #
# Component is now fully constraint and assembled # 

Assume you have have an active assembly test.asm where feature ID 43 is the subassembly sub.asm and contains a component with the name bolt.prt at feature id 30.

# Assembly test.asm is active
# '0' the path is invalid or
# '1' the path is valid.
set member1 [ps_assy component_name 43 ] set member2 [ps_assy component_name -model sub.asm -- 30 ] 

member1 will be set to SUB.ASM

member2 will be set to BOLT.PRT

Component Path

Create a component path object. A component path object identifies a unique component in one assembly.

# Note: creation or configuration return 0 or 1. # '0' the path is invalid or
# '1' the path is valid.
ps_comppath myPath -model test.asm -path {43 30} -component bolt.prt 

Export to file

  Export Data

Options for ps_export are:

 relation Filename model_info Filename program Filename iges_2d Filename dxf Filename render Filename sla_binary Filename sla_ascii Filename catiafacets Filename bom Filename dwg_setup Filename feature_info Filename mfg_oper_cl Filename mfg_feat_cl Filename material Filename iges_3d Filename step Filename vda Filename set Filename cgm Filename inventor Filename fiat Filename connector_params Filename catia Filename cable_params Filename optegra_vis Filename dwg Filename -help
  Geometric Data - Access geometrical data (x,y,z value)

Options for ps_data are:

 axis Geom_ID lineObj edge Geom_ID lineObj arc Geom_ID arcObj csys Geom_ID csysObj surface Geom_ID csysObj point Geom_ID pointObj outline lineObj eval_surface Geom_ID UVpointObj lineObj extremes Geom_ID pointObj lineObj edge_eval_xyz IDs Params curve_eval_xyz IDs Params edge_dir SurfID EdgeID curve Geom_ID lineObj tessellation Geom_ID Tolerance -help 


  Matrix and Point (Vector) object, collinear axis within an assembly

This command will create a 4x4 identity matrixObj

Options for matrixObj are:

 cget Option configure Option ?Value? rot2d angle invert normalize ?matrixOut? reset identity copy matrixOut product matrixObj ?matrixOut? x_to_vector pointObj y_to_vector pointObj z_to_vector pointObj origin_to_vector pointObj x_from_vector pointObj y_from_vector pointObj z_from_vector pointObj origin_from_vector pointObj shift_to_vector pointObj shift_from_vector pointObj scale_xyz ScaleValue

Sample command

# copy the matrix
matrixObj copy bckMatrix

Common problem to get collinear axis within an assembly

# Seach for collinear axis
# Input: # a) The Selection for the Axis to search for selAxis
# b) The Selection which gives us the part where we need to search in
# From the axis we get Matrix up to root
# Next the Matrix Down to our target
# Multiplay this two matices
# Transform with this matrix the given axis
# Search this in our target model #
# For planes, if the z vector is parallel
# it should have the same orientation
# we can use also the z-vector and one axis
# proc Collinear_Axis_Get {selAxis selModel} { #
# set up object vars
# Matrix obj's set MAT1 ::PS::TMP::MAT_1 set MAT2 ::PS::TMP::MAT_2 set MAT3 ::PS::TMP::MAT_3 # for axis data set AxisData1 ::PS::TMP::AXISDATA1 set AxisDataTmp ::PS::TMP::AXISDATATMP set AxisTrans ::PS::TMP::AXISTRANS #
# get model item from selection
# set mi1 [$selAxis cget -modelitem] set mi2 [$selModel cget -modelitem] # # get comp path from selection
# set cp1 [$selAxis cget -comppath] set cp2 [$selModel cget -comppath] #
# '$cp1 cget -model' and '$cp2 cget -model' should be the same assy
# ps_assy matrix_get -model [$cp1 cget -model] -bottom_up yes $cp1 $MAT1 ps_assy matrix_get -model [$cp2 cget -model] -bottom_up no $cp2 $MAT2 #
# Get target matrix
# $MAT1 product $MAT2 $MAT3 #
# get model item data
# set MODEL1 [$mi1 cget -model] set TYPE1 [$mi1 cget -type] set ID1 [$mi1 cget -id] set MODEL2 [$mi2 cget -model] #
# Input axis data
# ps_data axis -model $MODEL1 -- $ID1 $AxisData1 # # Transform this into the target model
# $AxisData1 transform $MAT3 $AxisTrans # # init list
# set collAxis [list] #
# get all axis in target
# set AllAxisInModel2 [ps_visit axis -model $MODEL2] foreach Axis $AllAxisInModel2 { ps_data axis -model $MODEL2 $Axis $AxisDataTmp set is_coll [$AxisTrans is_coll $AxisDataTmp] if {$is_coll == 1} { lappend collAxis $Axis } } #
# return all colinear axis
# return $collAxis
} # create selection objects
ps_sel sel1
ps_sel sel2 # Ask for an axis
sel1 select axis # ask for a part
sel2 sel part #
# get Collinear Axis based on sel1 and sel2
# Collinear_Axis_Get sel1 sel2

Similar commands available for arcs, coordinate systems, and single line (2 Points)

Options for pointObj are:

 cget Option configure ?Option? transform matrixObj pointObj rotate matrixObj pointObj copy pointObj product pointObj angle pointObj lenght normalize cross_product point2Obj resultPointObj dircos add point2Obj resultPointObj move point2Obj resultPointObj diff point2Obj resultPointObj 2d_values XY_List 3d_values XYZ_List multiply matrixObj pointObj draw ?Color? -help 
  Feature - Access basic feature information

Command options for ps_feat are:

 count name FeatIDs type FeatIDs list exists FeatIDs children FeatID parents FeatID status FeatIDs visible FeatIDs active FeatIDs number FeatIDs has_geom_checks FeatIDs suppress FeatIDs delete FeatIDs resume FeatIDs protype FeatIDs subtype FeatIDs show_param selObj ParamType set_name FeatID NewName is_read_only FeatIDs unset_read_only set_read_only FeatID ungroup GroupIDs groupstatus FeatIDs isgroup FeatIDs num_section FeatID section_copy FeatID secNumber sectionObjName cancel_insert_mode ?BoolResume? is_insert_mode insert_mode_activate FeatID -help
# Children of a feature in the active model
ps_feat child 23 #
# Parents from FeatID 45 in model box.prt
ps_feat parents -model box.prt -- 45 # # get the status for all features in the active model
set stat [ps_feat stat [ps_feat list]] #
# Set the first csys equal to model name (one line)
# ps_feat set_name [lindex [ps_visit type csys] 0] [file root [ps_model cur]] #
# better do a small procedure
# the call 'ps_visit type csys' will return all IDs in the model which are a csys
# In this sample only the first one needs to be checked
# If we don't have a csys the first element of the list is empty as well
# proc FirstCsysNameToModelName { Model } { if {![ps_model is_solid -model $Model] } { return } set FirstCsys [lindex [ps_visit type -model $Model csys] 0 ] if { [llength $FirstCsys ] == 0} { return } set NewName [file root $Model] set CurName [ps_feat name -model $Model -- $FirstCsys] if {[string compare $CurName $NewName] } { ps_feat set_name -model $Model -- $FirstCsys $NewName } } #
# Now call it with current model
# FirstCsysNameToModelName [ps_model cur] #
# Walk through an assembly
# proc Traverse {model} { set CompIDs [ps_visit type -model $model component] ;# Get all Component Feat ID's foreach CompID $CompIDs { # get component name set CompName [ps_assy component_name -model $model $CompID] ;# Get the model name by Feat ID # get the extension set ext [ps_model ext -model $CompName] switch $ext { PRT { FirstCsysNameToModelName $CompName } ASM { FirstCsysNameToModelName $CompName Traverse $CompName } default { error "Invalid extension '$ext' in assy '$model' found" return } } } return } #
# Now call it with current assembly model
# Traverse [ps_model cur] 


  Files - Open, save, erase Creo files

Options for ps_file are:

 open Filename erase Filename exists Filename save Filename delete Filename display Filename copy Source Target rename Source Target backup Filename NewDir create Filename get ?Filter? ?InitPath? ?Label? ?PreSelect? -help

Note: Get working directory with 'ps_pwd' and change with 'ps_cd TargetDir'

# open file from disc into memory
ps_file open c:/workdir/box.prt

Selection of Creo geometric elements

  Selection - Ask user to select, or fill model item info or component path info

Invoke a user selection

# create the selection object
ps_sel selObj #
# The usr should select an edge
# Wirite something into the Creo message area
# ps_mess "Please select an edge" #
# Control goes to Creo
selObj select edge # Back in p-Shell:
# Get the model item from the selection object
# Note: You can also get the status if a user abort.
selObj modelitem miObj #
# It's an edge - get the edge data into an lineObj
# Note: the line object will contains more info, calculate length is only one option
# ps_data edge -model [miObj get -model] -- [miObj get -id ] lineObj #
# get the vector length
set len [lineObj len]