**p-Shell - A Tcl Programming Interface to PTC's Creo Parametric** '''Scripting, Customization and Automation using Tcl scripts in Creo''' p-Shell is a http://www.ptc.com/cad/creo%|%Creo%|% Toolkit Application which runs synchronous or a-synchronous with Creo 4.0 - 7.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 (or connect to an existing session), 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.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''' or view https://www.youtube.com/channel/UC97mLPJak54nCYnMJ7xhiig/videos%|%YouTube Channel%|% ---- ***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.csv like box.prt.csv # if delimeter is not given, use “,” proc ExportModelParameter {model {del ,} } { # open the file for writing set fp [open $model.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] ] { # from the paramObj get name, value and the type set nam [$paramObj cget -name ] set val [$paramObj cget -value ] set typ [$paramObj cget -type ] # Write name, type and value into the file puts $fp [join [list $nam $typ $val] $del] } # close the file and return close $fp } # # call the export function for models names where the pattern match # # Get parameter for each Part model in session # proc ExportParameter {pattern} { # Loop through all files found by the given pattern foreach model [ps_glob $pattern] { # Call to export the parameter from one model ExportModelParameter $model } } # # Call the export procedure with the pattern “*.prt” # ExportParameter *.prt exit ====== Or by a button call (without exit of course) ====== pack [button .pexp -text „App Exp“. -command [list ExportParameter *.prt]] ====== 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 wiki.tcl.tk" -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" ====== Create a Component Parameter (Name PS_TEST_PARAMETER as a String with the Value 'TEST' at a selected component ====== ps_sel selObj -modelitem miObj selObj select part ps_param set -at miObj PS_TEST_PARAMETER String TEST ====== <> Access to Dimensions Console Help ====== ps_dim -help Options for ps_dim are: model exists DimID by_feat_ids FeatIDs from_ids DimIDs list thickness set ID_Val_List -help ====== An DimObj is created by calling ====== # get all from an ID, with a call to ‘ps_dim list’ upfront to loop through ID, Symbol, Value # you can give a pattern as well by just calling ‘ps_dim list -pattern hei*’ for example ps_dim dim from_id 1 # or get all dims from the feature with the ID 5 ps_dim dim by_feat_id 5 # the standard, to get all dim Objects from a Model is ps_dim model # to specify a different model use the -model option eq. from the motor.asm use ps_dim model -model motor.asm # for the ID or Feature Id ps_dim from_id -model box.prt —- 1 # or ps_dim by_feat_id -model motor.asm —- 5 ====== This will return an dimObj command like ::PS::BOX.PRT.DIM.D0 Other object specific commands: ====== Options for ::PS::BOX.PRT.DIM.D0 are: cget Option configure ?Option Value? reset model exists show noshow refresh drawing position move pointObj -help ====== To get the current dimension value call: ====== set value [::PS::BOX.PRT.DIM.D0 cget -value] ====== Read Write (RW) for cget and configure or Read Only (RO, e.g. you can’t change the type) options for cget only. Other cget/configure options follow here: ====== ::PS::BOX.PRT.DIM.D0 configure may return: {-value Value RW-Dim 0.0 360.0} {-bck_value BackupValue RO-Dim 0.0 360.0} {-symbol Symbol RW-Dim {} d0} {-is_ref_dim IsRefDim RO-Dim 0 0} {-is_iso_din ModelIsIsoDIN RO-Dim 1 0} {-type Type RO-Dim {} ANGLE} {-id DimID RO-Dim -1 0} {-featid FeatID RO-Dim 0 12} {-user_data UserData RW-Parameter {} {Model not ISO/DIN}} {-tolerance Tolerance RW-Dim {} {0.500000 0.500000}} {-symtext SymbolText RO-Dim {} {{{0:@D}}}} {-prefix DimPreFix RW-Dim {} {}} {-suffix DimSufFix RW-Dim {} {}} {-decimals Decimals RW-Dim 2 2} {-denominator Denominator RW-Dim -1 0} {-can_regen_driven_dim CanRegenDrivenDim RO-Dim -1 0} {-is_regen_negativ IsRegenNegativ RO-Dim -1 0} {-is_rel_driven IsRelationDriven RO-Dim -1 0} {-is_fractional IsFractional RO-Dim -1 0} {-inspection Inspection RW-Dim -1 0} {-basic Basic RW-Dim -1 0} {-comppath asmCompPath RW-AsmCompPath {} {}} {-view_id ViewID RW-Dim -1 -1} {-drawing Drawing RW-Dim {} {}} {-nominal NominalValue RO-Dim 0.0 360.0} {-bound Bound RW-Dim NOMINAL NOMINAL} {-label TolLabel RW-Dim {} {Model not ISO/DIN}} {-text Text RW-Dim {} {{{0:@D}}}} ====== Some sample code ====== # Just Do It for the current active model # with hardcoded seperator # export Id, symbol and value to csv proc DimShort {} { set out [file join [ps_pwd] Dim-[ps_model cur].csv] set fp [open $out w] foreach item [ps_dim list] { puts $fp [join $item ,] } close $fp } DimShort # with some note and a file header proc SimpleOut {model {sep {,}} } { # prepare the output filename # use the current working dir of Creo get by 'ps_pwd' # # and use the model name within the file name # if our current folder is c:/test and the model name is box.prt # out would be c:/test/SimpleDim-box.prt.csv # set out [file join [ps_pwd] SimpleDim-$model.csv] # open the file for write set fp [open $out w] # prepare a header, if not skip the next 2 lines of code # could be done in one line as well set COLS [list DimID DimSymbol DimValue] puts $fp [join $COLS $sep] # ps_dim list will return a list, each list item has 3 information # the dimension ID, the symbol name, and the value # e.g. # ps_dim list will return {6 d6 4.25} {10 boxlen 60.0} ... foreach item [ps_dim list -model $model] { puts $fp [join $item $sep] } # close the open file close $fp } # # export only dims for active features # Note: The the pattern dir value is not a dimension # # FeatID,DimID,DimSymbol,DimValue # 39,2,d2,32.0 # 39,3,d3,66.0 # 39,5,d5,7.5 proc ActiveOut {model {sep {,}} } { # prepare the output filename # use the current working dir of Creo get by 'ps_pwd' # # and use the model name within the file name # if our current folder is c:/Creo/Work and the model name is box.prt # out would be c:/Creo/Work/SimpleDim-box.prt.csv # set out [file join [ps_pwd] ActiveSimpleDim-$model.csv] # open the file for write set fp [open $out w] # prepare a header, if not skip the next 2 lines of code # could be done in one line as well set COLS [list FeatID DimID DimSymbol DimValue] puts $fp [join $COLS $sep] # Get all active feature IDs, skip suppressed ... set ActiveFeats [ps_feat list -active true] # this will return a nested list # foreach ActiveFeats ID a list of dims or an empty list set dimObjLists [ps_dim by_feat -model $model -- $ActiveFeats] # now check the list for each feat id foreach dimObjList $dimObjLists ActiveFeat $ActiveFeats { # if we have no dim for this feature continue if {[llength $dimObjList] == 0} continue # walk through the list of dimObj foreach dimObj $dimObjList { # get id, symbol and value set id [$dimObj cget -id] set sym [$dimObj cget -symbol] set val [$dimObj cget -value] # write to file puts $fp [join [list $ActiveFeat $id $sym $val] $sep] } } close $fp } # # export only a dimension value from type diameter # add tolernce values and inspection basic info # sample out (of course out is without the '#') # Symbol,Value,TolL,TolH,Inspection,Basic # d2,32.000,0.005334,0.005334,No,No # d12,5.334,0.005334,0.005334,No,No # d27,10.667,0.005334,0.005334,No,No proc SimpleByType {model {sep {,}}} { set B(0) No set B(1) Yes set dims [ps_dim list] set out [file join [ps_pwd] dim-info-by-type--$model.csv] set fp [open $out w] puts $fp "Symbol,Value,TolL,TolH,Inspection,Basic" foreach item $dims { # assign id sym val to a var from the list item foreach {id sym val} $item break # get the dim Object handle set dimObj [ps_dim from_ids -model $model -- $id] if {[string equal [$dimObj cget -type ] DIAMETER ] } { # get the tolerance set tol [$dimObj cget -tolerance ] # assign lower, upper value set toll [lindex $tol 0 ] set tolu [lindex $tol 1 ] #export if inspection or basic set insp [$dimObj cget -inspection ] set basic [$dimObj cget -basic ] set data [join [list $sym [format %.3f $val] $toll $tolu $B($insp) $B($basic)] $sep] puts $fp $data } } # close the file close $fp } DimShort SimpleOut [ps_model cur] ActiveOut [ps_model cur] SimpleByType [ps_model cur] ====== <> 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. [p-Shell Simple Attribute Viewer%|%width=696 height=444] ====== # 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 # AttrInit ====== 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 .4.1.2.1 -type DPOINT_PLA_CONSTRAINT -compound .4.1.2.1.1 -type DPOINT_PLA_CONSTR_REF -selection ::PS::FTREE::SEL.1 .4.1.2.1.2 -type DPOINT_PLA_CONSTR_TYPE -integer 0 .4.1.2.1.3 -type DPOINT_PLA_CONSTR_VAL -double 0.0 .4.1.2.2 -type DPOINT_PLA_CONSTRAINT -compound .4.1.2.2.1 -type DPOINT_PLA_CONSTR_REF -selection ::PS::FTREE::SEL.2 .4.1.2.2.2 -type DPOINT_PLA_CONSTR_TYPE -integer 0 .4.1.2.2.3 -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 .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 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 .4.1.2.1.1 -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 ====== ---- <> Create a Shrink Wrap Sample code to create a ShrinkWrap Model Output. ====== # Get the current model FOO.ASM set cur [ps_model cur] # Create ShrinkWrap Obj ps_shrinkwrap swObj # Create 2 modelitems Objs ps_modelitem CsysMiObj ps_modelitem PlanMiObj # Config 2 modelitems by name, one is a csys, one is a datum plane CsysMiObj byname $cur csys acs0 PlanMiObj byname $cur surface a-top # use this modelitems to create 2 Selection Objs ps_sel CsysSelObj -modelitem CsysMiObj ps_sel PlanSelObj -modelitem PlanMiObj # Create a random output filename (sec by sec) set outfile swrapout[clock sec].prt # Create this model in session ps_file create $outfile # config the shrinkwrap Output, Method, Target Solid swObj config -output_filename shrink_test_out -creationmethod merged -target_solid $outfile # Add the 2 Datum Selections swObj config -datumrefs [list CsysSelObj PlanSelObj] # Create the ShrinkWrap swObj export # Save it to disk ps_file save $outfile # clean all created objs ps_obj destroy * ====== ***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. ====== # # Delete all Drawing Tables which are belonging to the current Format # and sheet number Prior to replace the Format # Purpose is to remove the old Title Block # proc Delete_Format_Table_From_Sheet {DRAWING sheet} { set TABIDS [ps_table list -drawing $DRAWING ] foreach TABID $TABIDS { set is_from_format [ps_table is_from_format -drawing $DRAWING -- $TABID] if {$is_from_format} { set seg_count [ps_table segcount -drawing $DRAWING -- $TABID] # # Title Block should have a Segment Count of 1 # if {$seg_count == 1} { set seg_sheet [ps_table segsheetget -drawing $DRAWING -- $TABID -1] if {$seg_sheet == $sheet} { ps_table delete -drawing $DRAWING -- $TABID } } } } } # 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 -> {F126 FEATURE PS78047.PRT BOOL} {d9 DIMENSION PS78047.PRT DOUBLE} {MATERIAL PARAMETER PS78047.PRT STRING} # get ids 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/release.pro # # 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 # set ClockVal [clock format [clock seconds] -format "%m/%d/%y"] ps_param set -model box.drw -- DRW_RELEASE_DATE String $ClockVal # # 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 ====== ---- ***Assemblies*** <> 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 # including named model items # one for the assembly reference # one for the component reference ps_sel AssySelObj -modelitem AssyMiObj ps_sel CompSelObj -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 # # 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 ****Replace Component(s)**** ====== # # Some! notes and assumption for a component interchange # # Your current active model is an assembly # The model name given by CurModel is part of the assembly # The model name given by NewModel is loaded and already in session # Note: # The components are replaced only in the top level # of the given assembly (not recursive) # # If the CurModel is an instance or the genric, # NewModel must be in the same family table or the generic # It will Fail if CurModel is equal to RepModel # If the CurModel is part of an interchange assembyl, # NewModel must be in the same interchange assembly # ID Table Map still valid # You must have a PTC lizense (AdvAssembly) to do an interchange # ... # # A proc just to call our small test function # proc ReplaceModelTest {} { set Assy [ps_model cur] set CurModel PSL053.PRT set RepModel PSL060.PRT ReplaceModel $Assy $CurModel $RepModel } # # This is the basic task # More check are required # to make it save # e.g. # RepIDs is not initialized # Component feature status may invalid (suppressed, name retrieve may fail) # RepModel may not in session # Is the RepModel valid for Replace (same table, interchange assembly) # ... proc ReplaceModel {Assy CurModel RepModel} { # Visit by Component will return all # component IDs in the given assembly foreach ID [ps_visit type -model $Assy component] { # Get the model Name for the given ID in this assembly set M [ps_assy comp -model $Assy $ID] #If the component name is equal to CurModel add to our list if {[string equal -nocase $M $CurModel]} {lappend RepIDs $ID} } # Do the Interchange ps_assy interchange -model $Assy -- $RepIDs $RepModel return } ====== Replace by Family Table with some checks ====== # For the given Assembly # Get the component IDs # for the given Model Name # # Args: # # Assy - The Assembly where to replace the model # Model - The Assembled Model to Replace # ReplaceModel - The Target Model Name after Replace # Assumption: # If Model is not an Instance it is a Generic # ... proc ReplaceByFamTab {Assy Model ReplaceModel} { set IDs [IDsByModelName $Assy $Model] if {[llength $IDs] == 0} { Rep_Error "Model $Model not found in Assembly" return 1 } set GenModel $Model # If the given model is an instance get the generic if { [ps_model is_instance -model $Model] == 1} { set GenModel [ps_model generic_get -model $Model] } # Get access to the Family Table ps_famtab FTObj -model $GenModel # Init the list by the name with out extension set InstNames [file root $GenModel] # Add all other instance names foreach Inst [FTObj names] { lappend InstNames $Inst } # Check that the model to replace is part # of the instance list, hithout the Extension check if {[lsearch $InstNames [file root $ReplaceModel]] < 0} { Rep_Error "Replace Model $ReplaceModel not found in the generic model $GenModel" return 1 } # Make sure the model is in session if {![ps_model exists $ReplaceModel]} { Rep_Warn "Open Instance $ReplaceModel" FTObj open [file root $ReplaceModel ] } # Do the Interchange ps_assy interchange -model $Assy -- $IDs $ReplaceModel return 0 } # # Get Component IDs # in a given assemby # which match the given # 'Model' name # further checks for suppressed IDs # are required # proc IDsByModelName {Assy Model} { set RetIDs [list] foreach ID [ps_visit type -model $Assy component] { # Get the model Name for the given ID in this assembly set M [ps_assy comp -model $Assy $ID] if {[string equal -nocase $M $Model]} {lappend RetIDs $ID} } return $RetIDs } proc Rep_Error {mess} { ps_mess -icon err $mess } proc Rep_Warn {mess} { ps_mess -icon warn $mess } proc Rep_Mess {mess} { ps_mess $mess } ====== ****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 Quick sample: ====== # # Simple Creo Export Task # read from an input file the drawing name # Line by Line # # export the Drawing as DXF # and the attached models to STEP # Check if the the object was already export # # Export STEP and DXF files in different folder # # Main Call to export ddata from Creo files # proc DO_Export {} { global env global APP_GLOB if {![info exists env(WORKDIR)]} { error "env var WORKDIR not found" } destroy .log toplevel .log pack [text .log.t] set EXP_DIR [file join $env(WORKDIR) export] set APP_GLOB(EXP.ROOT) $EXP_DIR set APP_GLOB(EXP.DXF) [file join $EXP_DIR DXF] set APP_GLOB(EXP.DXF.LOG) [file join $APP_GLOB(EXP.DXF) Log] set APP_GLOB(EXP.STEP.DIR) [file join $EXP_DIR STEP] set APP_GLOB(EXP.STEP.LOG) [file join $APP_GLOB(EXP.STEP.DIR) Log] set APP_GLOB(EXP.INPUT.FILE) [file join $EXP_DIR Input input.csv] set APP_GLOB(EXP.DONE.FILE) [file join $EXP_DIR Input done.csv] set INPUT $APP_GLOB(EXP.INPUT.FILE) set DONE $APP_GLOB(EXP.DONE.FILE) Status_Set INF "Import from $INPUT, log in $DONE" # Check the required export folder, dirty hack if {![file isdir $APP_GLOB(EXP.ROOT)]} { file mkdir $APP_GLOB(EXP.ROOT) } if {![file isdir $APP_GLOB(EXP.DXF)]} { file mkdir $APP_GLOB(EXP.DXF) } if {![file isdir $APP_GLOB(EXP.DXF.LOG)]} { file mkdir $APP_GLOB(EXP.DXF.LOG) } if {![file isdir $APP_GLOB(EXP.STEP.DIR)]} { file mkdir $APP_GLOB(EXP.STEP.DIR) } if {![file isdir $APP_GLOB(EXP.STEP.LOG)]} { file mkdir $APP_GLOB(EXP.STEP.LOG) } if {![file exists $INPUT]} { Status_Set INF "Input file not exists '$INPUT'" return } # Read what was already don Creo_Export_Read_Done $DONE # Start the export Creo_Export_Start $INPUT } # Run proc Creo_Export_Start {INPUT} { set fp [open $INPUT] set data [split [read $fp] \n] close $fp set len [llength $data] foreach model $data { set MODEL [string toupper [string trim $model]] if {[string len $MODEL] == 0 } { continue } if {[string equal [string index $MODEL 0] #]} { Status_Set INFO "Skip '$MODEL' ($i/$len)" continue } Status_Set INFO "Export '$MODEL' ($i/$len)" after 500 Creo_Export_Action $MODEL } } proc Creo_Export_Action {MODEL} { global DONE_DATA if {[info exists DONE_DATA($MODEL) ]} { Status_Set INF "Already Done '$MODEL'" return } set EXT [string range $MODEL end-2 end] switch $EXT { DRW { if {[Creo_Export_Action_DRW $MODEL] == 1} { Creo_Export_Read_Mark $MODEL } } ASM - PRT { if {[Creo_Export_Action_ASM_PRT $MODEL] == 1} { Creo_Export_Read_Mark $MODEL } } } } proc Creo_Export_Action_DRW {MODEL} { global APP_GLOB set InSession [ps_model exists $MODEL] if {$InSession == 0} { set ok [Creo_Open_File $MODEL] if {$ok == 0} { return 0 } } set root [file rootname $MODEL] set Rev X-X # Export DXF if {[ps_param exists -model $MODEL PTC_WM_VERSION]} { set POBJ [ps_param list -model $MODEL PTC_WM_VERSION] set Rev [$POBJ cget -val] } set Rev [string map {. {-}} $Rev] set filename [format "%s_%s.%s" $root $Rev dxf] set dirname $APP_GLOB(EXP.DXF) set export [file join $dirname $filename] # Create the DXF file set fail [catch {ps_export dxf -model $MODEL -- $export}] if { $fail == 1} { Status_Set ERR "DXF Export for '$MODEL' fail" return 0 } set logfiles [glob -nocomplain -tail -dir $dirname *_dxf__out.log*] foreach logfile $logfiles { set src [file join $dirname $logfile] set tar [file join $APP_GLOB(EXP.DXF.LOG) $logfile] if {[file exists $tar]} { catch {file delete $tar} } catch { file rename $src $tar Status_Set INF "Move Log Info to log folder" } } Status_Set INF "DXF Export for '$MODEL' success" set AttachedModels [ps_draw list -drawing $MODEL] set ret 1 foreach Model $AttachedModels { if {[Creo_Export_Action_STEP $MODEL] == 0} { set ret 0 } } return 1 } # Open a file # search path must be set or from Windchill # proc Creo_Open_File {TAR_FILE} { if { [ catch {ps_file open $TAR_FILE } ] } { Status_Set ERR "Can't open $TAR_FILE" return 0 } Status_Set DEB "Successfully loaded '$TAR_FILE'" return 1 } # # Export Action for a 3D Model # proc Creo_Export_Action_ASM_PRT {MODEL} { global APP_GLOB Status_Set INF "STEP Export for '$MODEL' ..." set InSession [ps_model exists $MODEL] if {$InSession == 0} { set ok [Creo_Open_File $MODEL] if {$ok == 0} { return 0 } } set ret [Creo_Export_Action_STEP $MODEL] return $ret } # # export 3D model as a STEP File # Check for Windchill Revision Info # Use the Rev in the output filename # proc Creo_Export_Action_STEP {MODEL} { set root [file rootname $MODEL] set Rev X.X # Export DXF if {[ps_param exists -model $MODEL PTC_WM_VERSION]} { set POBJ [ps_param list -model $MODEL PTC_WM_VERSION] set Rev [$POBJ cget -val] } set Rev [string map {. {-}} $Rev] set filename [format "%s_%s.%s" $root $Rev stp] set dirname $::APP_GLOB(EXP.STEP.DIR) set export [file join $dirname $filename] set fail [catch {ps_export step -model $MODEL -- $export}] if { $fail == 1} { Status_Set ERR "STEP Export for '$MODEL' fail" return 0 } set logfiles [glob -nocomplain -tail -dir $dirname *_out.log*] foreach logfile $logfiles { set src [file join $dirname $logfile] set tar [file join $::APP_GLOB(EXP.STEP.LOG) $logfile] if {[file exists $tar]} { catch {file delete $tar} } catch { file rename $src $tar Status_Set INF "Move Log Info to log folder" } } Status_Set INF "STEP Export for '$MODEL' success" return 1 } # # Mark already done proc Creo_Export_Read_Mark {MODEL} { set fp [open $::APP_GLOB(EXP.DONE.FILE) a+ ] puts $fp $MODEL close $fp } proc Creo_Export_Read_Done {DONE} { global DONE_DATA unset -nocomplain DONE_DATA if {![file exists $DONE]} { Status_Set INF "Already Done Info not exists" return } Status_Set INF "Read Already Done Info ..." set fp [open $DONE] set data [split [read $fp] \n] close $fp foreach model $data { set MODEL [string toupper [string trim $model]] if {[string len $MODEL] == 0 } { continue } set DONE_DATA($MODEL) 1 Status_Set INF "Mark as Done '$MODEL'" } } # Simple logger proc Status_Set {type message} { .log.t insert end "$type $message\n" update } # run for it DO_Export ====== ---- <> 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 ---- <> Pattern ====== # Assume you have a point table pattern # and you want to export the x,y,z coords for each point # Note: 3d values measured in default transformation of the model # # if 235 is a point pattern feature ID in the current model # open file for export set fp [open export.txt w] # Get all Feature IDs part of the pattern foreach member [ps_pattern member 235] { # Get the geom point ID set geomId [ps_visit feature point $member] # Get the coords in a point Object ps_data point $geomId pntObj # Write x y z to the open file puts $fp [pntObj 3d] } # close the open file close $fp ====== ***Matrices*** <> Matrix and Point (Vector) object, collinear axis within an assembly ====== ps_matrix matrixObj ====== This command will create a 4x4 identity matrixObj &|1.0|0.0|0.0|0.0|& &|0.0|1.0|0.0|0.0|& &|0.0|0.0|1.0|0.0|& &|0.0|0.0|0.0|1.0|& 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*** <> 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 ====== ====== # # open files from a text file # model names one per line # # Note: If you work with Windchill # NAME.EXT is enough in a connected session # # If you work with search path # you can use the full path as well # # # read the file # set fp [open models.txt] set models [split [read $fp] \n] close $fp # # Open the models in session # if already in session skip to open the model # foreach model $models { if {![ps_model exist $model]} ps_file open $model } } ====== ---- ***Selection of Creo geometric elements*** <> Selection - Ask user to select, or fill model item info or component path info, highlight 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] ====== Just highlight assembly components at the first level for the active assembly ====== ps_sel sel -modelitem mi -color warning # In this case it works without setting the model item type # The default is 'UNUSED' foreach featid [ps_visit type component] { mi config -id $featid sel show } ====== ---- <> External Data - Write your own Data into a model file (like a SQLite DB) Write a test string and a whole SQLite DB (or any other file) to the model. Note: You can write tcl scripts to the model as well and use 'eval' later. This example shows how to read and write in one call, so this is only an example. An Application may read first, and later write the updated database back to the Creo file. Only on Init a new Database may writen to the file or if the structure of the DB have changed. You can use any 'Class' or 'Slot' name (max 32 char), it up to you. The max size per slot is 524288 bytes and you can have not more than 11800 slots. Available commands (without options) ====== ps_exdata class_create ClassName ps_exdata class_delete ClassName ps_exdata class_list ps_exdata create Slot ps_exdata delete Slot ps_exdata list ps_exdata read Slot ps_exdata write Slot Data ====== Example code ====== proc Write_Read_SQLITE_Slot {} { # The current Model set M [ps_model current] # Write a Text to the model ps_exdata write -model $M -class MyClass -- MySlot "This is my Data" # Read it back set mydata [ps_exdata read -model $M -class MyClass -- MySlot] # Read the SQLite DB set fp [open [file join c:/MyApps DB mydb.sqlite ]] fconfigure $fp -translation {binary binary} set data [read $fp] close $fp # Encode set encdata [base64::encode $data] # Write into the model ps_exdata write -model $M -class MyClass -- MyFileSlot $encdata # Read Back set encdata [ps_exdata read -model $M -class MyClass -- MyFileSlot] # Decode set decdata [base64::decode $encdata] # Open a model name based SQLite file # Write the content back to disc set fp [open [file join c:/MyApps DB Model.$M.sqlite ] w] fconfigure $fp -translation {binary binary} puts $fp $decdata close $fp } ====== <> Mapkeys - Use Mapkey in Asynchronous mode ====== # # In synchronous mode mapkey’s will be executed # after the control returns to Creo # # In a-synchronous mode you can write complete # programs using map key’s. # The macro is immediately executed # # # A-Synchronous Mode # There are three programming options # to use Mapkey’s (which I would prefer) # # 1. Call the Mapkey directly # 2. Create a config file on the fly, then read the file and execute the key # 3. Use substr and replace all your variables in a string # Next save/or execute # This sample shows option 1 and a commented version of option 2 # # Mode 1 # # In the mode you can easily create a proc’s where the arguments # are the variable you need in your mapkey # for example on ‚file open‘ the name of the file may your argument # # Use ‚tail -f‘ (get a windows version ) on your current trail file # If you record a mapkey a lot of stuff is not needed # Watch the statements # Write your code and Test your sub routines proc Run {} { package req pshell_asyn ps_session sessionObj sessionObj connect # For some logs pack [text .t] -expand yes -fill both ps_cd [pwd] # Main Call MK_Action } # # Main Action, Hardcoded here # Input where ever you get the full path from # proc MK_Action {} { set files [list] lappend files c:/CreoTickle/work/models/blower.asm lappend files c:/CreoTickle/work/models/frame.prt lappend files c:/CreoTickle/work/models/nut.prt lappend files c:/CreoTickle/work/models/piston_pin.prt foreach file $files { MK_Quit_Window # Run the Mapkey MK_Change_Dir [file dirname $file] # Or write on the fly a config file # MK_Change_Dir_By_Config_File [file dirname $file] MK_File_Open [file tail $file] MK_File_Save_As STEP } # MK_Quit_Window } # Execute the Mapkey # log what we do here # proc MapKey {MK} { .t insert end [split $MK \;] .t see end # Next Call will invoke the mapkey ps_mapkey $MK } # # Write a Config File # proc MK_Write {CFG sequence} { set fp [open $CFG w] puts $fp $sequence close $fp } # Read a Config File proc MK_Read {CFG} { ps_import config $CFG } # Write/Read and Execute proc MK_Change_Dir_By_Config_File {dir} { # Name of the MapKey set MK ps_cd set CFG [file join [pwd] mapkey.pro] set sequence " mapkey $MK ~ Close `main_dlg_cur` `appl_casc`;\\ mapkey(continued) ~ Command `ProCmdSessionChangeDir` ;\\ mapkey(continued) ~ Trail `UI Desktop` `UI Desktop` `DLG_PREVIEW_POST` `file_open`;\\ mapkey(continued) ~ Update `file_open` `Inputname` `$dir`;\\ mapkey(continued) ~ Command `ProFileSelPushOpen@context_dlg_open_cmd`; " # Write to a config file MK_Write $CFG $sequence # Read it MK_Read $CFG # Execute it MapKey %$MK return } # Close Active Window proc MK_Quit_Window {} { MapKey "~ Command `ProCmdWinCloseGroup`" } # Close Diaplod proc MK_Close {} { set sequence "~ Close `main_dlg_cur` `appl_casc`;" MapKey $sequence } # # Save current Model either IGES or STEP # proc MK_File_Save_As {Type} { switch -glob -nocase -- $Type { STEP { set DB_Key db_539 } IGES { set DB_Key db_134 } default { error "Invalid Type '$Type', use STEP or IGES" } } append sequence "~ Close `main_dlg_cur` `appl_casc`;" append sequence "~ Command `ProCmdModelSaveAs`;" append sequence "~ Open `file_saveas` `type_option`;" append sequence "~ Close `file_saveas` `type_option`;" append sequence "~ Select `file_saveas` `type_option` 1 `$DB_Key`;" append sequence "~ Activate `file_saveas` `OK`;" append sequence "~ Activate `UI Message Dialog` `ok`;" MapKey $sequence return } # # Open a file # Note: Ths will not work for an instance # proc MK_File_Open {MODEL} { append sequence "~ Command `ProCmdModelOpen`;" append sequence "~ Update `file_open` `Inputname` `$MODEL`;" append sequence "~ Activate `file_open` `Inputname`;" MapKey $sequence MapKey "~ Command `ProFileSelPushOpen_Standard@context_dlg_open_cmd`;" } # # Simply change the current # working folder # proc MK_Change_Dir {dir} { append sequence "~ Close `main_dlg_cur` `appl_casc`;" append sequence "~ Command `ProCmdSessionChangeDir` ;" append sequence "~ Trail `UI Desktop` `UI Desktop` `DLG_PREVIEW_POST` `file_open`;" append sequence "~ Update `file_open` `Inputname` `$dir`;" append sequence "~ Command `ProFileSelPushOpen@context_dlg_open_cmd`;" MapKey $sequence return } Run ====== <> CAD