The scripting interface is mainly a bunch of Tcl procedures and Tcl commands that a big part of Ayam uses internally.
Using Tcl, you could directly modify the code Ayam consists of. This is, however, not recommended for good reasons. So watch out for already existing procedures and commands when implementing your own!
Using procedures and commands not listed in this documentation is dangerous too. Implementation and interfaces of that commands may change in future versions.
The scripting interface may be used directly from the console
of Ayam. You can, of course, also write procedures in your own
Tcl script files, that may be loaded at any time into Ayam using
the console and the Tcl command "source"
.
You can also arrange for a script to be executed automatically
on startup using the preference setting "Main/Scripts"
.
Note that most of the listed commands work in background, without changing anything to the Ayam GUI and Ayam view windows, for execution speed. If you want your changes to become visible you have to update the various parts of the GUI explicitly (see also section Updating the GUI).
From scripts it may be necessary to check wether an error occured
during the execution of a command. All commands return
TCL_OK in any case so checking their return value avails to nothing,
but they set the global Tcl variable ay_error
to a value
higher than 1 if an error occured. You need to set it to zero before
and check it after the operation in question to see whether the
operation performed successfully.
Several global variables exist in the Ayam Tcl context, that may be useful for scripts.
The global array "ay"
holds application state variables.
Furthermore, you can find the paths to important widgets
(e.g. the tree widget for the object hierarchy or the currently
active view) in this array.
Use "parray ay"
in the console to see what is there.
More documentation to come.
The global array "ayprefs"
holds preferences data.
The complete array is saved in the "ayamrc"
file upon exit,
so be careful when adding new entries.
You can reset your "ayamrc"
file anytime using the command line
option "-failsafe"
.
Use "parray ayprefs"
in the console to see what is there.
More documentation to come.
More documentation to come.
To create new objects the "crtOb"
command can be used.
"crtOb type [args]"
"crtOb"
,
type may be derived from the type name, as displayed in the tree view.
Depending on the type, further arguments may (or have to) be given, other types expect objects to be selected:
"NCurve"
: NURBS curves accept a single integer as length of
the new curve, the length defaults to 4. Example:
"crtOb NCurve -length 10; uS; rV"
"NPatch"
: NURBS patches accept two integers as width and
height of the new patch, width and height both default to 4. Example:
"crtOb NPatch -width 2 -height 2; uS; rV"
"Level"
: Levels must be given an additional argument
determining the type of the new level, this argument may be one of:
"0"
(level), "1"
(union), "2"
(intersection),
"3"
(difference), "4"
(primitive)."Material"
: Materials must be given an additional
argument giving the name of the new material. Example:
"crtOb Material default; uS; rV"
"Instance"
: creates an instance of the selected object.This command is probably the most important one, because a lot of the other commands operate on selected objects only.
selOb - select object(s):
"selOb [index]"
withOb - work on certain selected object(s):
"withOb index command"
Every property has a corresponding global array, where the data of the property is saved. This global array only holds useful data when the respective property GUI is active, or when it has been filled explicitly by the so called get-property callback. The data may be transferred back to the selected object using the so called set-property callback. The names of the array and the callbacks may be inferred from another global array that is named like the property itself, e.g. for the tags property the following global array is defined:
array set Tags { arr tagsPropData sproc setTagsp gproc getTagsp w fTagsAttr }
If sproc or gproc are empty (""
), a standard callback
named "setProp"
or "getProp"
should be used.
The following global arrays and callbacks to get or set the data exist:
These commands operate the object clipboard:
copOb - copy object:
"copOb"
cutOb - cut object:
"cutOb"
pasOb - paste object:
"pasOb"
delOb - delete object:
"delOb"
cmovOb - paste (move) object:
"cmovOb"
The following commands operate the object property clipboard, which is totally independent from the object clipboard.
pclip_copy - copy a property to the clipboard
"pclip_copy mode"
pclip_paste - paste a property
"pclip_paste"
"pasteProp"
.These commands manipulate the current level of Ayam.
goDown:
"goDown index"
goUp:
"goUp"
goTop:
"goTop"
movOb - move objects:
"movOb dx dy dz"
rotOb - rotate objects:
"rotOb dx dy dz"
scalOb - scale objects:
"scalOb dx dy dz"
movSel - move selected points:
"movSel dx dy dz"
rotSel - rotate selected points:
"rotSel dx dy dz"
scalSel - scale selected points:
"scalSel dx dy dz"
delegTrafo - delegate transformations:
"delegTrafo"
applyTrafo - apply transformations:
"applyTrafo sel|all"
shaderSet:
"shaderSet shadertype [varname]"
"surface"
, "displacement"
,
"light"
, "imager"
, "atmosphere"
, "exterior"
or "interior"
. If varname is not given, the shader in question
is deleted from the object instead.shaderGet:
"shaderGet shadertype varname"
"surface"
, "displacement"
,
"light"
, "imager"
, "atmosphere"
, "exterior"
or "interior"
. The shader will be written to an array
pointed to by varname.addTag:
"addTag type value"
""
as value parameter. This is e.g.
needed for the "NoExport"
tag.delTags:
"delTags type"
"all"
, all tags are deleted from the
currently selected objects(s).getTags:
"getTags tvname vvname"
setTags:
"setTags tags"
clampNC:
"clampNC"
elevateNC:
"elevateNC n"
insknNC - insert knot:
"insknNC u r"
U[p] <= u <= U[n]
, where
p is the degree (order-1) of the curve and n is the length of the curve.
The knot type of the curves will always be changed to custom but
the shape of the curves will not change!refineNC:
"refineNC [{u1 u2 un}]"
revertNC:
"revertNC"
rescaleKnNC:
"rescaleKnNC"
"Custom"
!
This operation does not change the shape of the curve.splitNP:
"splitNP (u|v)"
buildNP:
"buildNPatch"
Use these two commands to read or manipulate single points of arbitrary objects. Note that the exact arguments needed, depend on the type of the object, e.g. a NURBS curve requires just one index parameter (indexu), whereas a NURBS patch requires two (indexu and indexv).
getPnt:
"getPnt [-trafo] indexu [indexv] varx vary varz [varw]"
"-trafo"
is given, the coordinates
will be transformed by the values given in the objects
Transformation property.setPnt:
"setNP indexu [indexv] x y z [w]"
rV - redraw all views:
"rV"
uS - update select:
"uS [update_prop maintain_selection]"
If update_prop is 0 no update of the property GUIs will take place. If maintain_selection is 1 the old selection will be established again. If both arguments are omitted update_prop defaults to 1 and maintain_selection to 0.
"ay(ul)"
(UpdateLevel) may be set
to the current level before calling "uS"
. This will not remove
and update the complete scene but just the part below "ay(ul)"
.
Example:
global ay; set ay(ul) $ay(CurrentLevel); uS;
"uCR"
may be used instead of "uS"
."uCL cl"
may be used instead of "uS"
.uCL - update current level:
"uCL mode [args]"
"uS"
above.
The parameter "mode"
may be "cl" or "cs", where "cl" is the normal
operation mode, and "cs" just clears the selection.uCR - update current level after create:
"uCR"
"uS"
above.plb_update - property listbox update:
"plb_update"
io_lc - load custom:
"io_lc filename"
There are two commands that help to apply arbitrary commands to a number of objects, forAll and forAllT.
forAll:
"forAll recursive command"
"forAllT"
in this case."forAll 0 { uplevel #0 { commands } }"
"forAll 0 { global arrayname; commands }"
forAllT:
"forAllT type recursive command"
Note that the type strings will be converted to lowercase before comparison, so that it is legal to use forAllT e.g. this way:
"forAllT ncurve 0 {puts $i}"
"forAllT ncurve 0 {uplevel #0 {commands} }"
"forAllT ncurve 0 { global arrayname; commands }"
newScene:
"newScene"
replaceScene:
"replaceScene filename"
insertScene:
"insertScene filename"
saveScene:
"saveScene filename"
ayError:
"ayError code place detail"
getType:
"getType varname"
tmpGet:
"tmpGet tmpdir varname"
hasChild:
"hasChild"
undo:
"undo [redo|save|clear]"
"redo"
, this command performs the redo
operation."save"
, the currently selected objects
are saved to the undo buffer for future undo operations."clear"
, the undo buffer is cleared.convOb:
"convOb [-inplace]"
"-inplace"
is
used the new object(s) will replace the old object(s).forceNot:
"forceNot"
Here are some example scripts for the Ayam Tcl scripting interface.
You may copy and paste all examples directly from the documentation into the console of Ayam.
The following example script shows how to move a selected object to a specified position in space.
proc placeOb { x y z } { global transfPropData # copy Transformations-property data to # global array "transfPropData" getTrafo # set array values according to procedure parameters set transfPropData(Translate_X) $x set transfPropData(Translate_Y) $y set transfPropData(Translate_Z) $z # copy Transformations-property data from # global array "transfPropData" to selected object setTrafo } # placeOb
forAll 0 {placeOb 1 1 1}
"placeOb"
procedure (defined above) with them:
global ay $ay(cm) add command -label "Place Object" -command { runTool {x y z} {"X:" "Y:" "Z:"} "forAll 0 {placeOb %0 %1 %2}" uS }
The following example script snippet shows how to move control points of a NURBS curve.
# first, we create a new NURBS curve with 30 control points set len 30 crtOb NCurve -length $len # update selection uS # select last object (the newly created curve) sL # prepare moving set i 0 set r 3.0 set angle 0 set angled [expr 3.14159265/2.0] while { $i < $len } { set x [expr $r*cos($angle)] set y [expr $r*sin($angle)] set z [expr $i/3.0] # move control point to new position setPnt $i $x $y $z 1.0 set angle [expr $angle + $angled] incr i } # redraw all views rV
The following example script shows how to easily create a sweep from a selected path curve (avoiding the manual and lengthy creation and parameterisation of a suitable cross section).
proc easySweep { } { # first, we create a sweep object crtOb Sweep # now, we need to move the selected curve (path) to # the sweep and create a cross-section curve there too # for that, we move the currently selected curve to the clipboard cutOb uS # how does the current level look like? getLevel a b # enter the Sweep (the last object in the current level) goDown [expr [llength $a]-1] uS # now, we create a new curve (a closed BSpline suitable as cross section) crtClosedBS 8 uS # how does the current level look like? getLevel a b # select last object (the newly created curve) selOb [expr [llength $a]-1] # now, we rotate and scale the curve rotOb 0 90 0 scalOb 0.25 0.25 1.0 # move trajectory back (we use "cmovOb" and _not_ "pasOb", because we # really move (and not copy) the curve cmovOb # go up to where we came from goUp # update GUI uS sL # redraw all views rV } # easySweep
Run this pocedure by selecting a NURBS curve object, then type into the console:
easySweep
You may add this command to the main menu as well:
global ay $ay(cm) add command -label "Easy Sweep" -command { easySweep }
Custom/Easy Sweep
that calls the easySweep
procedure.
Here is another example that shows how you may add buttons to the tool box. myImage should be an image created e.g. from a GIF file of the size 25 by 25 pixels.
global ay # create an image from a GIF file: image create photo myImage -format gif -file /home/user/a.gif set b .tbw.f.mybutton # if the button not already exists: if { ![winfo exists $b] } { # create it: button $b -padx 0 -pady 0 -image myImage -command myCommand # tell Ayam about the new button: # you can use linsert, to insert the button in a specific # place or just append to the end of the list lappend ay(toolbuttons) mybutton # display the button: # from now on, it will be under the # automatic tool box layout management toolbox_layout }
This example shows that a) buttons have to be created in the
frame ".tbw.f"
b) Ayam manages a list of all buttons in the global array ay
in "ay(toolbuttons)"
, the order in that list is the order
in which buttons appear in the tool box c) automatic layout
management is carried out by the procedure "toolbox_layout"
.
Adding buttons with just text is a little bit more involved, as the sizes of the new buttons often do not fit well in the icon button scheme with its constant button size.
Here is an example that adds two buttons to the bottom of the tool box spanning the whole window (this works best with the standard tool box layout of 4 by 12 buttons):
# create a frame: set f [frame .tbw.f.fcollex] # create two buttons inside the frame: button $f.b1 -width 5 -text "Coll." -command { collNC; rV; } button $f.b2 -width 5 -text "Expl." -command { explNC; rV; } pack $f.b1 $f.b2 -side left -fill x -expand yes # calculate the row number below the last row: set row [expr [lindex [grid size .tbw.f] 1] + 1] # now display the frame at calculated row, spanning the whole window: grid $f -row $row -column 0 -columnspan [lindex [grid size .tbw.f] 0]