Next Previous Contents

6. Scripting Interface

The Ayam scripting interface consists of a number of Tcl procedures and Tcl commands that are also used internally by the application. For instance, the main menu entry "File/New" calls the scripting interface command "newScene" (among other commands). Using the Ayam scripting interface means to call these procedures or commands, possibly in a mix with standard Tcl script code.

Furthermore, using Tcl and its introspection capabilities, the code Ayam consists of could easily be modified at runtime. This is, however, not recommended for good reasons (unless intimate knowledge about the Ayam source code is obtained first). 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 those procedures and commands may change in future versions of Ayam without notice.

In Tcl, all variables, procedures, and commands are case sensitive, it really is "sL" and not "sl" and not "SL".

The scripting interface may be used directly from the console of Ayam. One can, of course, also put scripts in Tcl script files, that may be loaded at any time into Ayam using the console and the Tcl command "source". Script files can also be made to run on every application startup automatically using the preference setting "Main/Scripts". Moreover, on the X11 and Aqua window systems, Ayam is able to execute script code sent via the Tk "send" command or the AppleScript "tell" command from external applications.

In contrast to other modelling environments, in Ayam there is yet another way to run scripts. In Ayam, scripts may also be attached to Script objects and run when the notification mechanism updates the scene. See also section Script object. Even normal objects can trigger scripts upon notification using BNS or ANS tags. See also sections Before Notify Script and After Notify Script.

Note that most of the scripting interface commands listed in this documentation work in the background, without changing anything to the Ayam GUI and Ayam view windows, for the sake of execution speed. To make any changes to the scene visible, the various parts of the GUI (property GUIs, view windows) need to be updated explicitly (see also section Updating the GUI).
However, since Ayam 1.13 it is also possible to automatically run GUI updating commands in the console with every issued command by using <Shift+Return> instead of <Return>.
Also note that even though no updates of the GUI take place when using the scripting interface, all notification processes are carried out immediately regardless. The scene will be consistent and up to date when the scripting interface command returns.

Scene changes from the scripting interface can also be recorded in the undo buffer, but this must be arranged manually too (see the documentation of the undo command: Undo).

From scripts it may be necessary to check whether an error occurred 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 occurred. This variable needs to be set to zero before and checked after the operation in question to see whether the operation performed successfully, see the following example:


proc myProc { } {
  set ::ay_error 0
  copOb
  if { $::ay_error > 1 } {
    ayError 2 "myProc" "Error copying object!"
  }
}

6.1 Global Variables and Arrays

Several global variables and arrays exist in the Ayam Tcl context, that may be useful for scripts.

 

Global Variables

The global variable "ay_error" holds the current error state. See also section Reporting Errors.

The global variable "i" is used by all "forAll" command variants. See also section Applying Commands to a Number of Objects.

The global variables "u" and "v" are set by the find u/uv actions. See also sections Finding Points on Curves and Finding Points on Surfaces.

 

The Global Array ay

The global array "ay" holds application state variables. Furthermore, the paths to important widgets can be found (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

The global array "ayprefs" holds preferences data. The complete array is saved in the ayamrc file upon exit, so be careful when adding new elements to this array. See also section Ayamrc File. Use "parray ayprefs" in the console to see what is there. More documentation to come.

Note that changes to this array on the Tcl side do not immediately take effect as the data needs first to be transferred to the C context using the "setPrefs" command. See also section Managing Preferences.

 

The Global Array aymark

The global array "aymark" holds a copy of the current mark position.[∗] It is updated whenever the mark is set using e.g. the set mark action (see section Setting the Mark). Manual changes to this array have no effect on the mark.

 

Property Management and Data Arrays

For every object type, a corresponding global variable exists, that contains the property names of this object type as a list. The variable name is just the object type name followed by _props (for properties). For example for the NCurve object type, this variable is named "NCurve_props" and the list it contains looks like this:

{ Transformations Attributes Tags NCurveAttr }

This list is consulted each time a single object is selected in the tree view or object list widget and its content is used to populate the properties listbox widget. See also section Properties. Note that the list can be further manipulated by "NP" and "RP" tags of the selected object.

For every property, a corresponding global array exists, where the property is managed. For the Transformations property, this array looks like this:


Transformations {
  arr   transfPropData
  sproc setTrafo
  gproc getTrafo
  w     fTrafoAttr
}

The first entry, "arr", designates the name of the global property data array (thus, transformation data is stored in an array called "transfPropData"). This array only holds useful data when it has been filled explicitly by the so called get-property callback.

The entries "sproc" and "gproc" designate the set-property and get-property callbacks (procedures or commands). Those are called, when the "Apply" button is used or the property is selected in the properties listbox respectively. If sproc or gproc are empty strings (""), standard callbacks named "setProp" or "getProp" will/should be used to get or set the property values. But for the Transformations property, the "setTrafo" and "getTrafo" commands should be used. The flexibility gained by individual sproc/gproc procedures is used to sanitize user input, run additional GUI update code or realize dynamic property GUIs.

The last entry, "w", is the name of the main property GUI window. To get the full, usable, widget path of this window, the current value of the array entry "ay(pca)" needs to be prepended: $ay(pca).$Transformations(w).

Note that for many object types the property variable and the object type specific property management arrays only exist after an object type specific initialization procedure, derived from the type name, is called, e.g. "init_Box". Those types are: ACurve, Bevel, Birail1, Birail2, Box, BPatch, Cap, ConcatNC, ConcatNP, Cone, Cylinder, Disk, ExtrNC, ExtrNP, Hyperboloid, ICurve, IPatch, NCircle, OffsetNC, OffsetNP, PatchMesh, Paraboloid, Revolve, RiInc, RiProc, Script, SDMesh, Select, Sphere, Sweep, Swing, Torus, and Trim.

Since Ayam 1.16, the global property management array may be created easily using the new scripting interface command "addPropertyGUI". See also section Property GUI Management.

The following global arrays and callbacks to get or set the data exist:

propertyarrayget-property callbackset-property callback
TransformationstransfPropDatagetTrafosetTrafo
AttributesattrPropDatagetAttrsetAttrp
MaterialmatPropDatagetMatsetMat
TagstagsPropDatagetTagspsetTagsp
MaterialAttrMaterialAttrData""setMaterialAttrp
Surfaceay_shadershader_getSurfshader_setSurf
Displacementay_shadershader_getDispshader_setDisp
Interioray_shadershader_getIntshader_setInt
Exterioray_shadershader_getExtshader_setExt
Lightay_shaderlight_getShaderlight_setShader
LightAttrLightAttrDatalight_getAttr""
ViewAttribViewAttribData""setViewAttr
CameraCameraData""setCameraAttr
NCurveAttrNCurveAttrData""""
NPatchAttrNPatchAttrData""""
ICurveAttrICurveAttrData""""
NCircleAttrNCircleAttrData""""

Property Arrays and Callbacks

Note that this list is pretty much incomplete, however the information can always be inferred easily using the "parray" command in the Ayam console:

» parray NCurveAttr
See also section Manipulating Properties for more information on how to edit property values from the scripting interface.

6.2 Procedures and Commands

This section provides documentation on the most important scripting interface procedures and commands of Ayam sorted by category.

Note that the "help" command in the Ayam console can be used to directly jump to the appropriate sub-section of this part of the documentation.

All procedures and commands are documented in the following scheme:

 

Getting Help on Scripting Interface Commands

Since Ayam 1.8.2 a scripting interface command named "help" is available, that displays the help of scripting interface commands using a web browser (similar to the "Help on Object" feature):

 

Managing Objects

To create new objects the "crtOb" command can be used.


The following helper commands, create certain often used curves:

crtNCircle – create NURBS circle:


crtNParabola – create a parabola:


crtNHyperbola – create a hyperbola:


crtNConicArc – create a conic arc:


crtClosedBS – create closed (circular) B-Spline:


crtNRect – create a rectangular NURBS curve:


crtTrimRect – create a rectangular bounding trim curve:

The following helper commands create certain often used surfaces:


crtNSphere – create a sphere:


crtNCylinder – create a cylinder:


crtNCone – create a cone:


crtNDisk – create a disk:


crtNTorus – create a torus:


crtNParaboloid – create a paraboloid:


crtNHyperboloid – create a hyperboloid:


delOb – delete object(s):

 

Interrogating Objects

These commands help to inquire objects about various aspects.

getType:


getName:


hasChild:


hasMat – has material:


hasRefs – has references:


candelOb – delete object(s):


hasTrafo – has transformations:


isCurve:


isSurface:


getBB – get the bounding box:


getPlaneNormal – get the plane normal of an object:


isClosed:


isPlanar – check for planarity:


isDegen – check for degeneracy:


isParent:


isTrimmed:


isHidden:

 

Selecting Objects

These commands are probably the most important ones, because many other scripting interface commands operate on selected objects only:

selOb – select object(s):


sL – select last object:


hSL – hidden select last object:


sP – hidden select parent object:

 

Selecting Points

This command manipulates the point selection.

selPnts – manage the point selection:

 

Selecting Faces

This command manipulates the face selection.

selFace – manage face selection:[∗]

 

Manipulating Properties

These procedures allow easy access to object properties from the scripting interface:[∗]

getProperty – get single property value


setProperty – set single property value

 

Clipboard Operations

These commands operate the object clipboard:

copOb – copy object(s):


cutOb – cut object(s):


pasOb – paste object(s):


repOb – replace clipboard content with selected object(s):


clearClip – clear object clipboard:


The following procedures operate the property clipboard, which is totally independent from the object clipboard.

copyProp – copy a property to the property clipboard


pasteProp – paste a property

 

Hierarchy Operations

These commands manipulate the current level of Ayam:

goDown:


goUp:


goTop:


The following commands move objects around in the hierarchy:

upOb – shuffle object(s) backward in the current level:


downOb – shuffle object(s) forward in the current level:

 

Transformations

These commands transform objects or selected points of objects:

movOb – move objects:


rotOb – rotate objects:


scalOb – scale objects:


movPnts – move selected points:


rotPnts – rotate selected points:


scalPnts – scale selected points:


delegTrafo – delegate transformations:


applyTrafo – apply transformations:


normTrafos – normalize transformation values:


normPnts – normalize points:


normVar – normalize variable(s):


normVal – normalize double value(s):

 

Manipulating Shaders

These commands operate the shader properties:

shaderSet:


shaderGet:

 

Manipulating Tags

These commands may be used to modify the tags of an object (see also section Tags).

When processing tags of unknown or unregistered type, a corresponding warning message may be emitted. This warning can be inhibited using the hidden preference setting "WarnUnknownTag" or by registering the tag type using the "registerTag" command (see below).

setTag:


addTag:


hasTag:


delTags:


getTags:

setTags:


getTag:


registerTag:

 

Manipulating Curves

These commands operate on parametric curves:

openC – open curve:


closeC – close curve:


refineC – refine curve:


coarsenC – coarsen curve:


revertC – revert curves:


shiftC – shift control points of a (closed) curve:


toXYC – rotate curve to XY-plane


concatC – concatenate curves:

 

Manipulating Surfaces

These commands operate on parametric surfaces:

revertuS – revert surfaces:


revertvS – revert surfaces:


swapuvS – swap dimensions of surfaces:


concatS – concatenate surfaces:


capS – cap surfaces:

 

Manipulating NURBS Curves

These are more specialized commands to change NURBS curve properties:

clampNC – clamp NURBS curve:


unclampNC – unclamp NURBS curve:


extendNC – extend NURBS curve:


elevateNC – increase order of NURBS curve:


reduceNC – decrease order of NURBS curve:


insknNC – insert knot into NURBS curve:


remknNC – remove knot from NURBS curve:


remsuknNC – remove superfluous knots from NURBS curve:


refineknNC – refine knots of NURBS curve:


tweenNC – interpolate (tween) curves:


rescaleknNC – rescale knots of NURBS curves:


splitNC – split NURBS curve


extrNC – extract NURBS curve:


trimNC – trim NURBS curve


estlenNC – estimate length of NURBS curve:


reparamNC – reparameterise a NURBS curve:


isCompNC:


makeCompNC – make NURBS curves compatible


interpNC – interpolate NURBS curve:


approxNC – approximate NURBS curve:


curvatNC – compute curvature:


torsionNC – compute torsion:


distNC – compute distance between two NURBS curves:[∗]


fairNC – improve curve shape:

 

Manipulating NURBS Surfaces

These are more specialized commands to change NURBS surface properties:

clampuNP – clamp NURBS patch in U direction:


clampvNP – clamp NURBS patch in V direction:


unclampuNP – unclamp NURBS patch in U direction:


unclampvNP – unclamp NURBS patch in V direction:


rescaleknNP – rescale knots of NURBS patches:


insknuNP – insert knot into NURBS patch:


insknvNP – insert knot into NURBS patch:


remknuNP – remove u knot from NURBS surface:


remknvNP – remove v knot from NURBS surface:


remsuknuNP – remove superfluous knots from NURBS surface:


remsuknvNP – remove superfluous knots from NURBS surface:


refineuNP – refine NURBS surface in U direction:


refinevNP – refine NURBS surface in V direction:


elevateuNP – elevate NURBS surface in U direction:


elevatevNP – elevate NURBS surface in V direction:


reduceuNP – decrease order of NURBS surface:


reducevNP – decrease order of NURBS surface:


splituNP – split NURBS patch:


splitvNP – split NURBS patch:


extrNP – extract NURBS patch:


tweenNP – interpolate (tween) surfaces:


interpuNP – interpolate NURBS surface in U direction:


interpvNP – interpolate NURBS surface in V direction:


approxNP – approximate NURBS surface:[∗]


breakNP – break NURBS patch into curves:


buildNP – build NURBS patch from curves:


isCompNP:


makeCompNP – make NURBS surfaces compatible


curvatNP – compute Gaussian curvature:


fairNP – improve surface shape:


tobasisPM – convert PatchMesh to a different basis:


tobasisBC – convert BCurve objects to a different basis:

 

Manipulating PolyMesh Objects

These are more specialized commands to change PolyMesh properties:

genfnPo – generate face normals:


gensnPo – generate smooth normals:


remsnPo – remove smooth normals:


flipPo – flip normals or loops:

 

Manipulating Points and Normals

Use these commands to read or manipulate the control points or normals of objects that support point editing.

getPnt – get point(s):


setPnt – set point(s):


getNormal – get normal(s):

setNormal – set normal:


getTangent – get first derivative(s)/tangent(s): [∗]

 

Vector Algebra

These procedures implement simple vector algebra for vectors stored as lists.

l3add – add two three element vectors:

l3sub – subtract two three element vectors:

l3mul – multiply two three element vectors:

l3scal – multiply a three element vector with a scalar:

l3dot – compute the dot product of two three element vectors:

l3cross – compute the cross product of two three element vectors:

l3to4 – convert 3D coordinates to rational style:

l4to3 – convert rational coordinates to 3D:

 

Updating the GUI

These procedures update various parts of the Ayam user interface:

rV – redraw all views:


uS – update select:


uCL – update current level:


uCR – update current level after create:


plb_update – property listbox update:

Since Ayam 1.13 it is also possible to automatically run GUI updating commands in the console by using <Shift+Return> instead of <Return>. The commands from the hidden preference setting "AUCommands" will be executed after the commands from the command line, if the <Shift> key is held down. <Shift+Return> may also be used without commands on the command line. By default, the "AUCommands" are "uS; rV;", leading to updated object tree, property GUI, and views.

 

Managing Preferences

These commands manage preferences data:

getPrefs – get preferences data:


setPrefs – set preferences data:

See also section Preferences

 

Custom Objects / Plugins

This command manages custom objects (plugins):

loadPlugin – load custom object / plugin:

 

Applying Commands to a Number of Objects

These procedures and commands help to apply arbitrary commands to a number of selected objects.

forAll:


withOb – execute a command on certain selected object(s):

 

Scene IO

These commands help to load scenes from and save them to Ayam scene files:

replaceScene:


insertScene:


saveScene:


newScene:

 

RIB Export

This command allows to export the current scene to a RenderMan Interface Bytestream (RIB):

wrib – RIB export:

 

Reporting Errors

This command is for error reporting from scripts:

ayError:

 

Property GUI Management

These procedures help to manage property GUIs. See also section Property Management and Data Arrays.

addPropertyGUI:


The following procedures add user interface elements to the property GUIs created by "addPropertyGUI".

addParam:


addString:


addCheck:


addColor:


addMatrix:


addMenu:


addFile:


addCommand:


addText:


addInfo:


addProgress:


addVSpace:


addOptionToggle:


addScriptProperty:

 

Miscellaneous

Miscellaneous commands:

convOb:


undo:


runTool:


notifyOb:


nameOb:


setMark:


getMark:


clearMark:


tmpGet:


whatis:


addToProc:

6.3 Expression Support in Dialog Entries

Various entries of dialogs for object creation and modelling tools support Tcl variables and expressions.

It is e.g. possible to enter


$::u

instead of a numeric knot value in the insert knot tool parameter dialog to infer the parametric value from the global variable u (that may have been set before using the find u modelling action) and insert a knot at the picked point.

It is also possible to enter complex mathematical expressions:


[expr sin(45)]

or call into own procedures (that have to return appropriately typed values):


[myproc]

where "myproc" is defined elsewhere (e.g. in a Tcl script file loaded via the "Scripts" preference setting) as follows:
proc myproc { } {
  return [expr sin(45)];
}

.

Repeated calling of the tool without opening the dialog (using the keyboard shortcut <Ctrl+T>), will execute the provided expression again. This means, a number of curves with increasing length can be created by entering into the Ayam console


set ::myvar 1

then entering for the length in the create NURBS curve dialog:
[incr ::myvar]

then pressing <Ctrl+T> multiple times.

6.4 Scripting Interface Examples

Here are some complete example scripts for the Ayam Tcl scripting interface.

All examples may be copied from the documentation and pasted directly into the console of Ayam.

 

Moving Objects

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

In order to move all selected objects to 1 1 1 you may enter the following into the console:
forAll -recursive 0 {placeOb 1 1 1}

But perhaps you would rather like a small GUI for that? No problem, the following snippet adds an entry to the custom menu that opens a small requester for the x-, y-, and z-values and calls the "placeOb" procedure (defined above) with them:
global ay
$ay(cm) add command -label "Place Object(s)" -command {
 runTool {x y z} {"X:" "Y:" "Z:"} {forAll -recursive 0 {placeOb %0 %1 %2};
   plb_update; rV
 } "Place Object(s)"
}

The trailing "plb_update; rV" command ensures that the GUI is updated properly and all views display the new position of the moved objects.

 

Moving NURBS points

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

Now use this as path for a Sweep. For instance, using the next small script.

 

Easy Sweep

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

 # enter the Sweep (the last object in the current level)
 goDown -1

 # now, we create a new curve (a closed B-Spline suitable as cross section)
 crtClosedBS -s 8

 # select the new object
 selOb 0

 # now, we rotate and scale the curve
 rotOb 0 90 0
 scalOb 0.25 0.25 1.0

 # move trajectory back (we use "-move", because we
 # really want to move (and not copy) the curve object
 pasOb -move

 # go up to where we came from
 goUp

 # finally, update the GUI...
 uS
 sL

 # ...and redraw all views
 rV
}
# easySweep

Run this procedure by selecting a NURBS curve object, then type into the console:

» easySweep

This command may be added to the main menu as well:


global ay
$ay(cm) add command -label "Easy Sweep" -command {
 easySweep
}

After running the above script there should now be a new menu entry "Custom/Easy Sweep" that calls the easySweep procedure.

 

Toolbox Buttons

Here is another example script that shows how buttons may be added to the toolbox. myImage should be an image created e.g. from a GIF file of the size 25 by 25 pixels.


global ay ayprefs

# create an image from a GIF file:
image create photo myImage -format gif -file /home/user/giffile

set b $ay(tbw).mybutton

# if the button does not already exist:
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 using "lappend"
  lappend ay(toolbuttons) mybutton

  # display the button:
  toolbox_layout

  # from now on, the button will be under the
  # automatic toolbox layout management
}

This example shows that

  1. toolbox buttons have to be created in a frame whose path and window name are stored in the global variable "ay(tbw)" (this is ".tbw.f" for multi-window GUI configurations or ".fv.fTools.f" for single-window GUI configurations),
  2. Ayam manages a list of all toolbox buttons in the global variable "ay(toolbuttons)", the order in that list is the order in which the buttons appear in the toolbox,
  3. 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 those buttons often do not fit well in the icon button scheme with its constant button size. However, the procedure "toolbox_add" can be of considerable help.[∗]

See also the script "scripts/topoly.tcl" for an example.

The following example script adds two buttons to the bottom of the toolbox spanning the whole window (this works best with the standard toolbox layout of 4 by 12 buttons used in the multi-window GUI configuration):


global ay

# create a frame:
set f [frame $ay(tbw).fcollex]

# calculate the row number below the last row:
set row [expr [lindex [grid size $ay(tbw)] 1] + 1]

# now display the frame at calculated row, spanning the whole window:
grid $f -row $row -column 0 -columnspan [lindex [grid size $ay(tbw)] 0]\
     -sticky we
# create two buttons inside the frame:
button $f.b1 -width 5 -text "Coll." -command { collMP; rV; }
button $f.b2 -width 5 -text "Expl." -command { explMP; rV; }
pack $f.b1 $f.b2 -side left -fill x -expand yes

6.5 Distributed Helper Scripts

This sections contains the documentation of some helper scripts that are distributed with Ayam.

The helper scripts may be run via the context menu of the console, the Tcl "source" command in the console, or the "Scripts" preference setting of Ayam on each start (the latter except for the so called external scripts "repairAyam.tcl", "bgconvert.tcl", and "aytest.tcl").

All other, internal scripts may be combined arbitrarily except for "kdialog.tcl", "zdialog.tcl", and "intfd.tcl", which are mutually exclusive.

 

Repair Ayam

The external Tcl script "repairAyam.tcl" may be used to repair the application state of Ayam, should it be stuck e.g. in an endless loop of Tcl error messages.[∗]

On Unix systems "repairAyam" may be started from any shell simply by typing

» ./repairAyam.tcl
or
» wish repairAyam.tcl
on the command prompt; if the script detects that it is running on Unix and not in Ayam it will send itself to the Tcl interpreter Ayam is running in using the Tk send command. On Mac OS X Aqua (not X11!) AppleScript events will be used instead of the Tk send command. If this does not work as expected "repairAyam.tcl" may still be run via the Ayam console (as on Win32).

On Win32 "repairAyam.tcl" has to be started from the Ayam console using the command:

» source scripts/repairAyam.tcl
or via the consoles context menu: "Console/Load File".

The script "repairAyam.tcl" should be considered a last resort to help saving the current state of modified objects.

The script will close all views, clean up the application state variables, reset the mouse cursor and the console prompt, and try to update important main window widgets.

Furthermore, the script will also clear the console and try to break potential endless loops running e.g. in the console or in Script objects.[∗]

After running "repairAyam.tcl" the scene (or the most important objects currently worked on) should be immediately saved to a new scene file, not the file currently loaded, using "File/Save As" or "Special/Save Selected") and Ayam should be restarted afterwards.

Simply saving the scene using "File/Save" or <Ctrl+s> should be avoided because views were possibly deleted.

 

Test Ayam

The external script "aytest.tcl" allows to test the Ayam implementation by creating objects with various combinations of parameters and executing standard operations and modelling actions on them.

 

Use Ayam as Command Line Converter

The external Tcl script "bgconvert.tcl" converts scene files from one 3D file format to another, with the help of Ayam which is running in the background.[∗]

In the most simple form, bgconvert may be used from a Unix command line (or shell script) like this:

» bgconvert.tcl infile.x3d outfile.dxf

The above command would load the X3D file "infile.x3d" into Ayam and export the scene as DXF file to "outfile.dxf".

For a successful conversion Ayam has to run and the plugins required for the import and export processes need to be available and properly configured (check the "Plugins" preference setting). The plugins necessary for the conversion will be loaded automatically.

Import and export options may also be given like this:

» bgconvert.tcl "infile.rib -p 1" outfile.dxf

In the example above the "-p 1" option switches on reading of partial RIB files.

Available options and their syntax may be inquired from the import and export plugin Tcl scripts (e.g. "plugins/rrib.tcl").

 

Shader Parsing

The Tcl script "slxml.tcl" switches the shader parsing machinery of Ayam to recognize XML based meta information embedded in shading language comments.[∗] This way, the shader database for the Material objects can be built up from shading language source files, instead of compiled shaders.
The XML tags will not be parsed by a real XML parser, so that well formedness is not an issue. However, the attributes must be ordered in a certain way. To specify a shader, use:

<shader type="stype" name="sname">
where stype is one of surface, displacement, volume, light, imager, or transformation and sname is the shader name that must also match the file name of the shader source file sans extensions.

To specify a shader parameter, use a line like:

<argument name="argname" type="argtype" value="argval">
where argname is the name of the parameter, argtype is one of float, string, matrix, color, point, normal, or vector and argval is the default value.

See also the following example shader source:


/* myshader.sl:
 *  Author: Randolf Schultz
 * <shader type="surface" name="myshader">
 * <argument name="Ka" type="float" value="0.5">
 * <argument name="Kd" type="float" value="0.9">
 * <argument name="ic" type="color" value="0 1 0">
 */
surface myshader(float Ka = 0.5, Kd = 0.9; color ic = color (0, 1, 0);)
{
  color mycolor;

  ...

  Ci = Cs*mycolor*(Ka*ambient()+Kd*diffuse(faceforward(normalize(N),I)));
}

The following restrictions/caveats (in contrast to the normal shader parsing) apply:

 

Convert Everything to Polygons

The script "topoly.tcl" recursively browses through the scene and converts everything to a polygonal representation.[∗]

After running the script, there is a new button in the toolbox named "ToPolyMesh". Additionally, there is a corresponding entry in the "Custom" main menu. Pressing the button or using the menu entry immediately starts the conversion process.

Since the changes of the conversion can not be undone, the conversion will not run if the scene contains unsaved changes.

The conversion will use the current parameters from the preference settings "SMethod", "SParamU", and "SParamV"; "TP" tags (if present) will override these parameters. TP tags may be created easily using the tesselation tool, see also section Tesselation Tool.

 

Convert Everything to NURBS patches

The script "tonpatch.tcl" recursively browses through the scene and converts everything to a NURBS patch representation effectively flattening the tool object hierarchy.[∗]

After running the script, there is a new button in the toolbox named "ToNPatch". Additionally, there is a corresponding entry in the "Custom" main menu. Pressing the button or using the menu entry immediately starts the conversion process.

Since the changes of the conversion can not be undone, the conversion will not run if the scene contains unsaved changes.

 

Restrict the Console

The script "2lcons.tcl" (for two line console) may be used to restrict the screen space occupied by the console.

Normally, the Ayam console is resized with the main window and occupies a varying amount of screen space. After running the script, the console will always resize to exactly two lines of text. Different values may be chosen easily by adapting the script.

 

Color the Focus Ring

The script "colfocus.tcl" (for colored focus) may be used to paint the focus ring in a more visible color.

After running the script, the focus ring will be painted in blue (instead of black): focused sub-windows (views, console, object tree) will be more easily recognizable. Other colors may be used by editing the script.

 

Decouple Hierarchy View Link

Link Button

The script "link.tcl" places a small button into the object hierarchy title area that controls the, otherwise permanent, link between the hierarchy and the views.[∗] If this button is disabled, selection actions and changes to the hierarchy or to the objects themselves (via the property GUI) do not result in redraw operations.

Toggling the state to "on" will result in a single redraw.

This script may be used with all other scripts that place buttons in the designated area. The buttons will be placed from the right to the left in the order of the script execution.

 

Shuffle Objects Up/Down

Shuffle Objects Up/Down Buttons

The scripts "shufup.tcl" and "shufdown.tcl" place small buttons into the object hierarchy title area that shuffle the selected objects up or down in the current level.[∗] See also the image above.

See also the discussion about multiple hierarchy button scripts in section Decouple Hierarchy View Link.

 

Open/Close All Tree Levels

Open/Close All Tree Levels Buttons

The scripts "opent.tcl" and "closet.tcl" place small buttons into the object hierarchy title area that allow to open and close all tree levels.[∗] See also the image above.

See also the discussion about multiple hierarchy button scripts in section Decouple Hierarchy View Link.

 

Automatic About Center Actions

The script "aac.tcl" (for automatic about center) may be used to switch all modelling actions to their about variants with the mark set to the center of the current selection automatically.

After running the script, invoking e.g. the scale 2D action using the shortcut <s> will:

The script modifies all rotate and scale actions (including their axis confined variants).

Note, that the mark is not reset to a new center, when the selection changes. After a selection change (e.g. by selecting points in a different view) simply restart the action to transform about the new center.

To rotate or scale about a different point than the center, the mark may still be set manually using <a>.

To temporarily disable the modified behavior, the global keyboard shortcut <F11> can be used.

 

Automatic Point Actions

Note that since the introduction of the "ScopeManagement" preference setting (see Modelling Preferences) in Ayam 1.30 this script is obsolete and kept only for backwards compatibility. Furthermore, to ensure complete compatibility this script will set the scope management mode to "Explicit" when loaded.

The script "apnt.tcl" (for automatic point) may be used to switch the modelling mode to point modelling automatically after a point selection.

After running the script, selecting (tagging) a point using the select point action (shortcut <t>) will automatically switch the view to point modelling so that the next modelling actions (e.g. move, via shortcut <m>) will always transform the points and not modify the objects transformations. Note that currently the switch to point modelling will also occur, if no points are actually selected, it is just the mouse click that counts.

Selecting all points via the keyboard shortcut <A> will additionally switch to point modelling and de-selecting all points via <N> will additionally switch to object modelling.[∗]

It is also still possible to switch back to object modelling anytime via the keyboard shortcut <o>.

To temporarily disable the modified behavior, the global keyboard shortcut <F12> can be used.

 

Save Selected Points

The script "ssp.tcl" (for save selected points) allows to save the point selection to tags of type SP.[∗]

After running the script, two new buttons appear in the toolbox that allow to save and restore the point selection respectively. See also the table below.

OperationIcon
Save
Restore

Save/Restore Selected Points

There are also two corresponding entries in the custom menu.

Note that the tags can be saved to scene files and also copied to different objects.

 

Revert Cursor Key Behavior

The script "rc.tcl" (for revert cursor) may be used to get more useful cursor key behavior in primary modelling views (parallel views).

After running the script, the keyboard shortcuts for rotating and panning in parallel views are swapped, e.g. just pressing <Left> key will then pan the view, instead of rotating it.

The shortcuts will be swapped again, when the view changes type to "Perspective".

 

Access Core Functions from the Toolbox

The script "zap.tcl" demonstrates, how arbitrary core functionality that is just available through a main menu entry or the scripting interface might be accessed easily via the toolbox window.

After running the script "zap.tcl", there will be a new toolbox button, labeled "Zap!", that simply runs the zap command (which iconifies the complete application).

 

Switch Dialogs to Kdialog

The script "kdialog.tcl" switches all file dialogs of Ayam to use the kdialog application of the KDE project instead of the native Tk file dialog.
The script also adds a custom main menu entry to revert any changes.

 

Switch Dialogs to Zenity

The script "zdialog.tcl" switches all file dialogs of Ayam to use the zenity application of the Gnome project instead of the native Tk file dialog.
The script also adds a custom main menu entry to revert any changes.

 

Switch File Dialogs to Tcl

The script "intfd.tcl" switches all file dialogs of Ayam to use the Tcl/Tk internal version instead of the native file dialogs provided by the operating system.

 

Use Aqsis from Application Directory

The script "useaqsisapp.tcl" sets up Ayam to use Aqsis from the application directory structure ("/Applications/Aqsis.app") on Mac OS X. This is the default installation location of Aqsis on Mac OS X.

The script adapts the executable and shader search paths. Furthermore, environment variables vital for Aqsis to work will be set up properly.

Note that the script does not change the "RIB-Export/Renderer" preferences, you still have to switch to Aqsis using the main menu "Special/Select Renderer" once.

 

Use Pixie from Library Directory

The script "usepixie.tcl" sets up Ayam to use Pixie from the "/Library/pixie" directory on Mac OS X. This is the default installation location of Pixie on Mac OS X.

The script adapts the executable, shared library, and shader search paths. Furthermore, environment variables vital for Pixie to work will be set up properly.

Note that the script does not change the "RIB-Export/Renderer" preferences, you still have to switch to Pixie using the main menu "Special/Select Renderer" once.

 

Replace Icons

The script "myicons.tcl" allows to replace icons of the Ayam user interface, e.g. toolbox icons, with user defined ones. The new icons must be GIF image files of size 25 by 25 and reside in the "icons" directory relative to the Ayam executable.

The names of the image files may be obtained from the script or by the following scripting interface command (in the Ayam console):

» image names

Action icon variants (e.g. for the scale about actions) can also be created automatically by changing the "createVariants" variable in the script file.

 

Dynamic Tree

The script "dtree.tcl" (dynamic/fast tree) replaces some of BWidgets tree code for faster interaction in scenes with many objects.

The original BWidget tree widget (and accompanying script code in Ayam) creates a canvas item for every object in the scene, even if it is not visible in the tree widget. Therefore, tree update operations that occur e.g. after loading of a scene or after drag-and-drop operations, can become very slow, when a scene has many objects.

If the dtree script is active, there are only as many canvas items as there are nodes visible in the current scroll region. Therefore, working with many objects in long lists becomes much faster for operations that require tree updates. However, operations like opening or closing sub trees or even just scrolling in the tree will become a bit slower, as canvas items need to be created constantly.

 

Control Vertex View

Control Vertex View Example

The script "cvview.tcl" (control vertex view) allows to view the control points of NURBS surface or curve objects as property, see also the image above.

The script currently supports the following object types: APatch, IPatch, NPatch, PatchMesh, ACurve, ICurve, NCurve, BCurve, and SDCurve. In addition also objects that provide NPatch/NCurve objects and show a NPInfo/NCInfo entry in their parameter property are supported.[∗]

If the script is loaded, there is a new entry in the "Custom" menu ("Add CVView to Object") that allows to add a new property ("CVView") to an individual surface or curve object.

The "CVView" property GUI displays all control vertices in a regular grid. The coordinates of each vertex will be shown when the mouse pointer hovers over it. This also works if the control points lump together in 3D space or have unusual values.

Additionally, the current point selection is visualized by painting the selected vertices in red and the selection may also be adjusted by clicking on the circles. Drag selection is also possible.[∗]

 

Curvature Plot

Curvature Plot Example

The script "curvature.tcl" allows to view the curvature of NURBS curves and NURBS curve providing objects as property, see also the image above.

If the script is loaded, there is a new entry in the "Custom" menu ("Add Curvature View to Object") that allows to add a new property ("Curvature") to an individual curve object.

The "Curvature" property GUI displays the curvature of the curve as live and interactive diagram. The diagram will be updated if the curve changes. The diagram can be zoomed by dragging with the leftmost mouse button and panned by dragging with the rightmost mouse button (in zoomed state). Zooming is also possible with the mouse wheel.

The zoomed state is conveyed by prepending/appending "..." to/on the respective label of the horizontal scale.

Note that when panning, the new section of the curve will be re-scaled to completely fill the Y-axis.

For NURBS curve objects the real knot value range will be shown on the x axis whereas for NURBS curve providing objects a relative knot value range ([0, 1]) will be displayed.

A click on the "k" label toggles between absolute and logarithmic scaling of the Y-axis.

There is a resize handle that allows to adapt the size of the diagram to the property canvas.

 

NURBS for X3DOM

X3dom NURBS Display

The "x3dom-nurbs" script implements the <NurbsPatchSurface> and <NurbsTrimmedSurface> X3D NURBS nodes for x3dom (see http://www.x3dom.org/) in JavaScript.
After loading of the scene into the web browser, the NURBS surfaces from these nodes are tessellated into <IndexedTriangleSet> nodes. This allows to directly publish NURBS models on the web without prior conversion to a polygonal representation which is cumbersome, inflexible, and leads to higher bandwidth consumption.

The tessellator is based on idea and example code from A. J. Chung and A. J. Field: "A Simple Recursive Tessellator for Adaptive Surface Triangulation" in Journal of Graphics Tools Vol. 5, Iss. 3, 2000.

The implementation spans four script files:

In order to use the tessellator just add the following to your XHTML file after inclusion of "x3dom.js":

 <script type="text/javascript" src="x3dom-nurbs-pool.js"/>
 <script type="text/javascript" src="x3dom-nurbs-nodes.js"/>

As the tessellator is fully automatic, no further adjustments are needed.

Proper XHTML files can be created using the X3D export in x3dom-mode, see section X3D (Web3D) export options.

While the tessellator runs in the background an initial polygonal representation that is directly derived from the control polygon of the NURBS surface is shown. Additionally, a busy prompt is displayed, see also the image below. As the busy prompt is derived from the x3dom loading prompt, it may also be styled with the "x3dom-progress" style in "x3dom.css".

X3dom NURBS Busy Prompt

The tessellation runs in so called webworkers, processes that run in parallel to the main browser thread, in order to not block user interaction and employ multi-core CPUs. The webworker pool is currently hard coded to only use three such webworkers at any given time. This value may be adapted easily in "x3dom-nurbs-pool.js" (e.g. if your average target CPU has more cores). Note that each webworker will tessellate a single NURBS surface, i.e. scenes with only one surface will not benefit from the parallelism.

By default, the tessellator tries to create a tessellation that represents all important surface features in a way that a visual inspection from mid to close viewing distance does not reveal the nature of the underlying triangular representation. This may be too fine/slow for objects that are never viewed from close distance or too coarse for very detailed objects.

Therefore, and in concordance with the respective suggestions of the X3D specification, the tessellation quality and speed may be adjusted using the "uTessellation" and "vTessellation" attributes of the <NurbsPatchSurface> or <NurbsTrimmedSurface> nodes as explained in the next sections.

Object Space Based Sampling

If no "uTessellation" attribute is specified, or its value is positive, the tessellator uses the so called object space sampling mode. In this mode the tessellator subdivides an initial set of triangles recursively until all edges of those triangles are shorter than a given threshold value (in object space). The threshold value is set automatically so that an object extending one unit by one unit in object space is subdivided to about 15 by 15 by two triangles. The "uTessellation" attribute value is simply multiplied into this automatically determined threshold.

Therefore "uTessellation" values larger than 1.0 lead to a coarser and faster tessellation, whereas values smaller than 1.0 lead to a finer and slower tessellation.

Note that in this mode the value of the "vTessellation" attribute is not considered at all.

Also note that in highly curved regions of the surface and at trim edges, even smaller triangles than determined by the edge length criterion may be created.

Parametric Space Based Sampling

If the "uTessellation" attribute value is negative, the tessellator switches to parametric space sampling. In this mode also the "vTessellation" attribute is considered.

As in the object space sampling mode an automatic threshold value is computed, but here the extension of the object in parametric space (i.e. the number of control points) is used. This actually results in two threshold values, one for each parametric dimension. The "uTessellation" and "vTessellation" attributes are multiplied into those thresholds.

Therefore, values larger than -1.0 (in absolute value) lead to a coarser and faster tessellation in the respective dimension. Values smaller than -1.0 (in absolute value) lead to a finer and slower tessellation in the respective dimension. This means a value of -2.0 leads to roughly half as many triangles compared to the default and a value of -0.5 leads to twice as many triangles when compared to the default in the respective parametric dimension.

As the edge length computation is simpler and no curvature analysis is taking place, the parametric space sampling is considerably faster than object space sampling.

Note that at trim curve edges even smaller triangles than determined by the edge length criterion may be created.

Additional Attributes

To aid in parameterisation of the "uTessellation" and "vTessellation" attributes, a "normalPerVertex" attribute can be added to the respective <NurbsPatchSurface> or <NurbsTrimmedSurface> node. This attribute will then also be set for the corresponding <IndexedTriangleSet> node that is created by the tessellator. If the value of this attribute is "false", x3dom will display this surface in a flat shaded style and the tesselated triangles will be visible allowing easier judgment and adjustment of the tesselation quality.

Restrictions and Implementation Deficiencies

Due to memoization of surface points, parametric values must not exceed:

1,7976931348623157×10308 / 10×1010 = 1,7976931348623157×10297

Texture coordinates are always directly derived from the parametric values.

Surface normals are not computed by the tessellator, but by x3dom. This can lead to normals that are off for very coarse tessellations but is much faster. Another benefit of this approach is, that normals in non-differentiable surface points (e.g. the poles of the standard NURBS sphere) do not flip.

There is no support for the following nodes:

6.6 Distributed Script Objects

These scripts implement Script objects, see also section Script Object.

 

Truncated Cone

Truncated Cone with ZMax 2.0

The file "tcone.tcl" is a Script object script that creates truncated cones with arguments similar to the cylinder primitive, see also the above image.

This script must be used in a Script object of type "Create" (see section Script Object). For convenience, there is also a property GUI; one must add a "NP" tag of value "TConeAttr" to the Script object to see it.

These are the parameters of the truncated cone:

Internally, the script creates a Hyperboloid; further information about conversion capabilities and RIB export may be found in section Hyperboloid.

An example scene file containing such an object is distributed with Ayam, see the file:
"ayam/scn/scripts/tcone.ay".

 

Disk with Hole

Disk with Hole Example

The file "hdisk.tcl" is a Script object script that creates a disk with a hole, also called an annulus. See also the above image.

This script must be used in a Script object of type "Create" (see section Script Object). For convenience, there is also a property GUI; one must add a "NP" tag of value "HDiskAttr" to the Script object to see it.

These are the parameters of the disk with hole:

Internally, the script creates a Hyperboloid; further information about conversion capabilities and RIB export may be found in section Hyperboloid.

An example scene file containing such an object is distributed with Ayam, see the file:
"ayam/scn/scripts/hdisk.ay".

 

Box with Cylindrical Topology

Box with Cylindrical Topology

The file "cbox.tcl" is a Script object script that creates a NURBS surface in the form of a box with a cylindrical topology, see also the image above.

This script must be used in a Script object of type "Create" (see section Script Object). For convenience, there is also a property GUI; one must add a "NP" tag of value "CBoxAttr" to the Script object to see it.

These are the parameters of the cylindrical box:

In contrast to the standard Box object, the cylindrical box converts to a single NURBS patch. However, this patch has poles and, consequently, shading artefacts may appear on the top and down side. Texturing this object is also challenging.

An example scene file containing such an object is distributed with Ayam, see the file:
"ayam/scn/scripts/cbox.ay".

 

NURBS Circle with Triangular Base

NURBS Circle with Triangular Base

The file "tcircle.tcl" is a Script object script that creates NURBS circles with a triangular base, see also the above image.

In contrast to the standard nine point NURBS circle with rectangular base, the triangular circle consists of just seven control points. This can save some memory, e.g. in long sweep objects. However, the parameterisation of the triangular circle is also slightly worse. Furthermore, only full circles that start on the positive X-axis are supported.

This script must be used in a Script object of type "Create" (see section Script Object). For convenience, there is also a property GUI; one must add a "NP" tag of value "TCircleAttr" to the Script object to see it.

These are the parameters of the triangular circle:

An example scene file containing such an object is distributed with Ayam, see the file:
"ayam/scn/scripts/tcircle.ay".

 

Helix

Helix Example

The script "helix.tcl" creates a NURBS curve that forms a helix, see also the above image.

This script must be used in a Script object of type "Create" (see section Script Object). There is also a property GUI provided; one must add a "NP" tag of value "HelixAttr" to the Script object to see it.

These are the parameters of the helix:

An example scene file containing such an object is distributed with Ayam, see the file:
"ayam/scn/scripts/helix.ay".

 

Spiral

Spiral Example

The script "spiral.tcl" creates a NURBS curve that forms a spiral, see also the above image.

This script must be used in a Script object of type "Create" (see section Script Object). There is also a property GUI provided; one must add a "NP" tag of value "SpiralAttr" to the Script object to see it.

These are the parameters of the spiral:

An example scene file containing such an object is distributed with Ayam, see the file:
"ayam/scn/scripts/spiral.ay".

 

Oval

NURBS Oval

The file "oval.tcl" is a Script object script that creates NURBS curves in the form of an oval, here: two half circles connected by straight lines, see also the above image.

This script must be used in a Script object of type "Create" (see section Script Object). For convenience, there is also a property GUI; one must add a "NP" tag of value "OvalAttr" to the Script object to see it.

These are the parameters of the oval:

An example scene file containing such an object is distributed with Ayam, see the file:
"ayam/scn/scripts/oval.ay".

 

FilletNC

NURBS Fillet Curve

The file "filletnc.tcl" is a Script object script that creates a fillet NURBS curve between two other curves with adjustable individual tangent lengths, see also the above image.

This script must be used in a Script object of type "Modify" (see section Script Object) and instances of the curves to connect should be children of the Script object. For convenience, there is also a property GUI; one must add a "NP" tag of value "FilletNCAttr" to the Script object to see it.

These are the parameters of the fillet:

An example scene file containing such an object is distributed with Ayam, see the file:
"ayam/scn/scripts/filletnc.ay".

If instead of two instances of individual curves, two instances of a single curve are present as children, the fillet will close the parameter curve. An example scene file of this special setup is distributed with Ayam, see the file:
"ayam/scn/scripts/filletncc.ay".

 

DualSweep

DualSweep Example

The file "dualsweep.tcl" is a Script object script that creates a NURBS surface from three parameter curves similar to birailing but with cross section curves perpendicular to both rails, see also the above image.

The first curve is the so called cross section. This curve must be planar and defined in the YZ-plane. It is the leftmost open curve in the upper example image.
The second curve is the first rail curve. This curve should start in the starting point of the cross section curve. It is the lower closed curve in the upper example image.
The third parameter curve is the second rail curve. This curve should start in the end point of the cross section curve. It is the upper closed curve in the upper example image.

This script must be used in a Script object of type "Modify" (see section Script Object). For convenience, there is also a property GUI; one must add a "NP" tag of value "DualSweepAttr" to the Script object to see it.

These are the parameters of the DualSweep:

An example scene file containing such an object is distributed with Ayam, see the file:
"ayam/scn/scripts/dualsweep.ay".

 

Translational Surface

Translational Surface Example

The script "tsurf.tcl" creates a translational surface from two parameter curves, see also the above image. The control points of the translational surface are created by copying the control points of the first curve n times, where n is the number of control points of the second curve, while also offsetting the points according to the offset of the nth control point to the first control point of the second curve.

The curves do not need to touch in any point, but if they start in the same point, the translational surface will interpolate both curves.

Rational parameter curves are currently not supported.

This script must be used in a Script object of type "Modify" (see section Script Object). As the surface is completely defined by the parameter curves, there are no additional parameters and there is, consequently, also no property GUI.

An example scene file containing such an object is distributed with Ayam, see the file:
"ayam/scn/scripts/tsurf.ay".

 

Extrusion along Normal

Extrusion along Normal Example

The script "extruden.tcl" extrudes a NURBS curve along its normal, see also the above image.
If the curve object has a MN tag, it will take precedence over the normal computation via "getPlaneNormal". This is faster and also allows to create sheared extrusions.[∗]

Internally, the script creates a Skin from two curves, therefore, arbitrarily oriented and non-planar curves are supported.

This script must be used in a Script object of type "Modify" (see section Script Object). For convenience, there is also a property GUI; one must add a "NP" tag of value "ExtrudeNAttr" to the Script object to see it.

These are the parameters of the extrusion:

An example scene file containing such an object is distributed with Ayam, see the file:
"ayam/scn/scripts/extruden.ay".

 

Create Polyhedrons from Conway Notations

Polyhedron generated from Conway notation: "jtD"

Since Ayam 1.18 there is a complete example script for the JavaScript scripting interface distributed as "polyhedron.js" which creates polyhedrons from Conway notations. The script is based on the online Polyhedron VRML generator by George W. Hart:
http://www.georgehart.com/virtual-polyhedra/conway_notation.html

This script must be used in a Script object of type "Create" (see section Script Object). For convenience, there is also a property GUI; to make this GUI visible a "NP" tag of value "PolyhedronAttr" must be added to the Script object.

The Conway notation defines a set of operations executed consecutively on a seed/basic shape. The script currently supports the following seeds and operations (information taken from George W. Harts fine web pages, see above).

Seeds:
The Platonic solids are denoted T, O, C, I, and D, according to their first letter. Other polyhedra which are implemented here include prisms: Pn, antiprisms: An, and pyramids: Yn, where n is a number (3 or greater) which must be specified to indicate the size of the base, e.g. , Y3=T, P4=C, and A3=O.

Operations:
Currently, d, t, k, a, j, s, g, e, b, o, m, r, and p are defined. They are motivated by the operations needed to create the Archimedean solids and their duals from the Platonic solids. The following tables explain the operations in more detail:

LetterNameDescription
ddualThe dual of a polyhedron has a vertex for each face, and a face for each vertex, of the original polyhedron, e.g. dC=O.
t / tntruncate all / just n-fold verticesTruncating a polyhedron cuts off each vertex, producing a new n-sided face for each n-fold vertex.
k / knkis all / just n-sided facesThe kis operation divides each n-sided face into n triangles. A new vertex is added in the center of each face.
aamboThe ambo operation can be thought of as truncating to the edge midpoints. It produces a polyhedron, aX, with one vertex for each edge of X.
jjoinThe join operator is dual to ambo, so jX=dadX=daX. jX is like kX without the original edges of X.
eexpandEach face of X is separated from all its neighbors and reconnected with a new 4-sided face, corresponding to an edge of X. An n-gon is then added to connect the 4-sided faces at each n-fold vertex.
ssnubThe snub operation can be thought of as eC followed by the operation of slicing each of the new 4-fold faces along a diagonal into two triangles. With a consistent handedness to these cuts, all the vertices of sX are 5-fold.
ggyroThe dual operation to s is g. g is like k but with the new edges connecting the face centers to the 1/3 points on the edges rather than the vertices.
bbevelThe bevel operation can be defined by bX=taX.
oorthoDual to e, oX=deX=jjX. oX has the effect of putting new vertices in the middle of each face of X and connecting them, with new edges, to the edge midpoints of X.
mmetaDual to b, m is like k and o combined; new edges connect new vertices at the face centers to the old vertices and new vertices at the edge midpoints.

Conway Notation Operations

LetterNameDescription
rreflectChanges a left-handed solid to right handed, or vice versa, but has no effect on a reflexible solid. So rC=C, but compare sC and rsC.
ppropellorMakes each n-gon face into a "propellor" of an n-gon surrounded by n quadrilaterals, e.g. pT is the tetrahedrally stellated icosahedron. Try pkD and pt6kT. p is a self-dual operation, i.e., dpdX=pX and dpX=pdX, and p also commutes with a and j, i.e. paX=apX.

Additional Operations

These abbreviated explanations were again taken from George W. Hart.

6.7 JavaScript Scripting Interface

This sections contains the documentation of the JavaScript scripting interface which is available after loading of the "jsinterp" plugin.

The JavaScript scripting interface exists since Ayam 1.18 and is based on the Mozilla SpiderMonkey JavaScript engine.

Upon loading, the "jsinterp" plugin creates one JavaScript context that lives (with all variables and objects defined therein) until Ayam exits.

 

Accessing JavaScript from Tcl and Script Objects

The JavaScript functionality may be accessed from the Tcl scripting interface via the "jsEval" command. The command can be used either to directly execute JavaScript code provided via the commands argument (Tcl code in bold):

» jsEval {var a = 0; a = a + 5.5; tclset("a", a);}
or to execute JavaScript code from a file:
» jsEval -f scriptfile.js

Note, that this command is not available in the safe interpreter.

Furthermore, Script object scripts may also be implemented in JavaScript, provided the first line of the script is a comment that instructs Ayam to use the JavaScript interpreter:

/* Ayam, use: JavaScript */
var a = 0;
...
Note that the JavaScript scripting context inherits the limitations of the calling Tcl context. For example, when running in a Script object, the following code fails:
tcleval("exit");
because the Tcl command "exit" is not available in the safe interpreter. The command will not fail, when the calling context is the main Tcl interpreter; one can e.g. type into the Ayam console:
» jsEval {tcleval("exit");}
and Ayam quits (see also section: Safe Interpreter).

 

JavaScript Functions

This subsection informs about the global functions additionally available in the Ayam JavaScript interpreter.

Those are converted Tcl commands (e.g. "crtOb()"), "tcleval()", "tclvar()", and "tclset()".

Converted Commands:
The functionality of Ayam is accessible from JavaScript via a larger set of global functions, named as the corresponding Tcl commands. For instance, Ayam objects can be created in JavaScript using a function call like this:

crtOb("NCircle");
or, with additional arguments:
crtOb("NCircle", "-radius", 3.0);
In general, all commands available in the safe Ayam Tcl interpreter are also available as function (refer to section Procedures and Commands for a more or less complete list of those commands).

Note that Tcl procedures are generally not available as global JavaScript function, but they can be called using "tcleval()" as documented in the next paragraph.

tcleval():
This global JavaScript function allows to evaluate arbitrary Tcl scripts, delivered as string argument:

var a = 42;
a = tcleval("puts " + a + "; return 5;");
tcleval("puts " + a);
/* expected output: 42 5 */
The "tcleval()" function provides access to all the functionality of Ayam that is just available as a Tcl procedure. Note that return values are properly transferred back to JavaScript according to the rules for data conversion as documented below. However, due to an intermediate conversion to string data, the overhead of such a call is considerable and bulk data transport should be arranged by other means, see below.

tclvar():
Using the JavaScript function "tclvar()" a link between a Tcl variable and a corresponding variable in the JavaScript context may be established. The "tclvar()" function essentially creates a write trace on the Tcl variable, so that changes on the Tcl side are always automatically reflected on the JavaScript side:

tclvar("a");
tcleval("set a 42");
tcleval("puts " + a);
/* expected output: 42 */
Mind that the corresponding variable on the JavaScript side does not exist until the first write operation on the Tcl variable occurs. The Tcl variable, in turn, does not have to exist, when the "tclvar()" function is called (i.e. all the work is done in the trace callback). If the variable name contains a namespace specifier, this namespace has to exist, when "tclvar()" is called.

Even though it looks a perfect fit, "tclvar()" can not be used to manage a property data array (if the array contains components to be saved to Ayam scene files). This is, because upon reading a scene file with such saved array items, the items will be read (and put into the Tcl context) before the script can establish the write trace using "tclvar()" and the data from the scene file never arrives in the JavaScript context. There is no easy way to get around this. A suggested way to manage a property data array is shown in the complete examples section below.

tclset():
The third global JavaScript function is "tclset()" that allows to efficiently set Tcl variables from the JavaScript context avoiding conversion to string data and back. For example:

var a = 3.3;
var b = new Array(1, 3, 5);
tclset("a", a);
tclset("b", b);
sets the Tcl variable "a" to the floating point value 3.3, and "b" to a list of integer values { 1 3 5 }.
Note that the variable names may also point to Tcl array elements, for instance
tclset("SphereAttrData(Radius)", 1.2);
sets the Radius element in the SphereAttrData array; or contain namespace specifiers, for example
tclset("::MyNameSpace::Radius", 1.2);
sets the Radius variable in the MyNameSpace namespace.

 

Data Conversion

When data is transferred from the Tcl to the JavaScript side (e.g. while converting return values of "tcleval()" or variable values linked via "tclvar()"), the following conversions are in effect: Scalar data types will be converted to their directly matching counterparts, except for Booleans, which will be converted to integer values. Lists will be converted to Array objects (nesting is allowed and will produce accordingly nested arrays). Associative arrays will be converted to objects with named properties. Unicode strings are currently not supported. See also the table below.

TclJavaScript
Boolean (true, false)Integer (1, 0)
Integer (2)Integer (2)
Double (3.14)Double (3.14)
String ("mystr")String ("mystr")
List ({0 1 2})Array ((0, 1, 2))
Array (mya(mye) = 0.1)Object (mya.mye = 0.1)

Tcl to JavaScript Data Conversions

When data is transferred from the JavaScript side to the Tcl side (e.g. as function argument), the following conversions are in effect: Scalar data types will be converted to their directly matching counterparts, Array objects will be converted to lists (nesting is allowed and will produce accordingly nested lists). Unicode strings and objects of a type other than Array (e.g. Boolean) are currently not supported. See also the following table.

JavaScriptTcl
Integer (2)Integer (2)
Double (3.14)Double (3.14)
String ("mystr")String ("mystr")
Array ((0, 1, 2))List ({0 1 2})

JavaScript to Tcl Data Conversions

The transport/conversion of object properties (to e.g. associative array elements) can be arranged manually like this:

var a = new Object();
a.b = 3.14;
tclset("a(b)", a.b);

 

Complete Examples

This section contains two complete examples for Script objects written in JavaScript.

For the first example use Script object type "Modify" and put a Sphere as child object of the Script object.


/* Ayam, use: JavaScript */
tclvar("SphereAttrData");
getProp();
if(SphereAttrData)
{
  tclset("SphereAttrData(ZMin)", -SphereAttrData.Radius);
  tclset("SphereAttrData(ZMax)", SphereAttrData.Radius);
  setProp();
}

The above script will make sure, that the ZMin and ZMax parameters of the Sphere object always match its radius.

First, a link from the original Sphere object property data array "SphereAttrData" is established, so that when "getProp()" (a converted Tcl Ayam command) is called, also the JavaScript object "SphereAttrData" is filled with meaningful data.
The next line (the if) is a safety measure that prevents the script from failing if the child object of the Script object is not a Sphere object.
Now the radius value is transferred back to Tcl directly into the property data array to the ZMin and ZMax entries respectively with the help of "tclset()".
Finally, the modified property is transferred back to the Sphere object again with a converted Tcl Ayam command "setProp()".

The next example shows, how to manage a property GUI in a JavaScript implemented Script object script. Use Script object type "Create" and add a tag "NP MyProp" to see the property GUI.


/* Ayam, use: JavaScript, save array: MyPropData */
var MyPropData = new Object();
if(!tcleval("info exists MyPropData;"))
{
  /* initial script run (but not when loaded from scene file!) */
  MyPropData.MyItem = tcleval("set MyPropData(MyItem) 1.0;");
  tcleval("set MyPropData(SP) {MyItem};");
}
else
{
  /* all following script runs (and also when loaded from scene file!) */
  MyPropData.MyItem = tcleval("set MyPropData(MyItem);");
}
if(!tcleval("info exists MyPropGUI;"))
{
  tcleval("set ::phw [addPropertyGUI MyProp \"\" \"\"];");
  tcleval("addParam $::phw MyPropData MyItem;");
}
crtOb("Sphere");
sL();
getProp();
tclset("SphereAttrData(Radius)", MyPropData.MyItem);
tclset("SphereAttrData(ZMin)", -MyPropData.MyItem);
tclset("SphereAttrData(ZMax)", MyPropData.MyItem);
setProp();

This example demonstrates how to manage property data using the JavaScript object variable "MyPropData". The property data can be saved to and read from Ayam scene files with the help of a mirroring array variable on the Tcl side (also named "MyPropData"). To make this work properly, the initialisation of the JavaScript object must be constrained to the first script run: when the property data was read from a scene file, initialisation must not be run, instead the read data must be fetched from the Tcl context. This is what the first "if" statement, checking for existence of the mirroring Tcl array variable, in above example is all about.

Following this scheme of dual mirroring data structures on the Tcl and JavaScript sides, now the property GUI is created, which is also constrained to just one script run by a similar "if" statement.

After the GUI, a Sphere object is created and parameterised according to the data in the property GUI, which is used as radius, zmin, and zmax value.

6.8 Lua Scripting Interface

This sections contains the documentation of the Lua scripting interface which is available after loading of the "luainterp" plugin.[∗]

Upon loading, the "luainterp" plugin creates one Lua context that lives (with all variables and objects defined therein) until Ayam exits.

 

Accessing Lua from Tcl and Script Objects

The Lua functionality may be accessed from the Tcl scripting interface via the "luaEval" command. The command can be used either to directly execute Lua code provided via the commands argument (Tcl code in bold):

» luaEval {a = 0; a = a + 5.5; tclset("a", a);}
or to execute Lua code from a file:
» luaEval -f scriptfile.lua

Note, that this command is not available in the safe interpreter.

Furthermore, Script object scripts may also be implemented in Lua, provided the first line of the script is a comment that instructs Ayam to use the Lua interpreter:

-- Ayam, use: Lua
a = 0
...
Note that the Lua scripting context inherits the limitations of the calling Tcl context. For example, when running in a Script object, the following code fails:
tcleval("exit")
because the Tcl command "exit" is not available in the safe interpreter. The command will not fail, when the calling context is the main Tcl interpreter; one can e.g. type into the Ayam console:
» luaEval {tcleval("exit")}
and Ayam quits (see also section: Safe Interpreter).

 

Lua Functions

This subsection informs about the global functions additionally available in the Ayam Lua interpreter.

Those are converted Tcl commands (e.g. "crtOb()"), "tcleval()", "tclvar()", and "tclset()".

Converted Commands:
The functionality of Ayam is accessible from Lua via a larger set of global functions, named as the corresponding Tcl commands. For instance, Ayam objects can be created in Lua using a function call like this:

crtOb("NCircle")
or, with additional arguments:
crtOb("NCircle", "-radius", 3.0)
In general, all commands available in the safe Ayam Tcl interpreter are also available as function (refer to section Procedures and Commands for a more or less complete list of those commands).

Note that Tcl procedures are generally not available as global Lua function, but they can be called using "tcleval()" as documented in the next paragraph.

tcleval():
This Lua function allows to evaluate arbitrary Tcl scripts, delivered as string argument:

a = 42
a = tcleval("puts " .. a .. "; return 5;")
tcleval("puts " .. a)
-- expected output: 42 5
The "tcleval()" function provides access to all the functionality of Ayam that is just available as a Tcl procedure. Note that return values are properly transferred back to Lua according to the rules for data conversion as documented below. However, due to an intermediate conversion to string data, the overhead of such a call is considerable and bulk data transport should be arranged by other means, see below.

tclvar():
Using the Lua function "tclvar()" a link between a Tcl variable and a corresponding variable in the Lua context can be established. The "tclvar()" function creates a write trace on the Tcl variable, so that changes on the Tcl side are always automatically reflected on the Lua side:

tclvar("a")
tcleval("set a 42")
tcleval("puts " .. a)
-- expected output: 42
Mind that the corresponding variable on the Lua side does not exist until the first write operation onto the Tcl variable occurs. The Tcl variable, in turn, does not have to exist, when the "tclvar()" function is called (i.e. all the work is done in the trace callback). If the variable name contains a namespace specifier, this namespace has to exist, when "tclvar()" is called.

Even though it looks a perfect fit, "tclvar()" can not be used to manage a property data array (if the array contains components to be saved to Ayam scene files). This is, because upon reading a scene file with such saved array items, the items will be read (and put into the Tcl context) before the script can establish the write trace using "tclvar()" and the data from the scene file never arrives in the Lua context. There is no easy way to get around this. A suggested way to manage a property data array is shown in the complete examples section below.

tclset():
The third global Lua function is "tclset()" that allows to efficiently set Tcl variables from the Lua context avoiding conversion to string data and back. For example:

a = 3.3
b = {1, 3, 5}
tclset("a", a)
tclset("b", b)
sets the Tcl variable "a" to the floating point value 3.3, and "b" to a list of integer values { 1 3 5 }.
Note that the variable names may also point to Tcl array elements, for instance
tclset("SphereAttrData(Radius)", 1.2)
sets the Radius element in the SphereAttrData array; or contain namespace specifiers, for example
tclset("::MyNameSpace::Radius", 1.2)
sets the Radius variable in the MyNameSpace namespace.

 

Data Conversion

When data is transferred from the Tcl to the Lua side (e.g. while converting return values of "tcleval()" or variable values linked via "tclvar()"), the following conversions are in effect: Scalar data types will be converted to their directly matching counterparts. Lists will be converted to array-tables (nesting is allowed and will produce accordingly nested tables). Associative arrays will be converted to tables with properly named keys. Unicode strings are currently not supported. See also the table below.

TclLua
Boolean (true, false)Boolean (true, false)
Integer (2)Integer (2)
Double (3.14)Double (3.14)
String ("mystr")String ("mystr")
List ({0 1 2})Array ({0, 1, 2})
Array (mya(mye) = 0.1)Table (mya.mye = 0.1)

Tcl to Lua Data Conversions

When data is transferred from the Lua side to the Tcl side (e.g. as function argument), the following conversions are in effect: Scalar data types will be converted to their directly matching counterparts, array-tables will be converted to lists (nesting is allowed and will produce accordingly nested lists). Sparse and mixed tables are currently not supported. Unicode strings are also currently not supported. See also the following table.

LuaTcl
Boolean (true, false)Boolean (true, false)
Integer (2)Integer (2)
Double (3.14)Double (3.14)
String ("mystr")String ("mystr")
Array ({0, 1, 2})List ({0 1 2})

Lua to Tcl Data Conversions

The transport/conversion of table entries (to e.g. associative array elements) can be arranged manually like this:

a.b = 3.14
tclset("a(b)", a.b)

 

Complete Examples

This section contains two complete examples for Script objects written in Lua.

For the first example use Script object type "Modify" and put a Sphere as child object of the Script object.


-- Ayam, use: Lua
tclvar("SphereAttrData")
getProp()
if SphereAttrData then
  tclset("SphereAttrData(ZMin)", -SphereAttrData.Radius)
  tclset("SphereAttrData(ZMax)", SphereAttrData.Radius)
  setProp()
end

The above script will make sure, that the ZMin and ZMax parameters of the Sphere object always match its radius.

First, a link from the original Sphere object property data array "SphereAttrData" is established, so that when "getProp()" (a converted Tcl Ayam command) is called, also the Lua object "SphereAttrData" is filled with meaningful data.
The next line (the if) is a safety measure that prevents the script from failing if the child object of the Script object is not a Sphere object.
Now the radius value is transferred back to Tcl directly into the property data array to the ZMin and ZMax entries respectively with the help of "tclset".
Finally, the modified property is transferred back to the Sphere object again with a converted Tcl Ayam command "setProp()".

The next example shows, how to manage a property GUI in a Lua implemented Script object script. Use Script object type "Create" and add a tag "NP MyProp" to see the property GUI.


-- Ayam, use: Lua, save array: MyPropData

if tcleval("info exists MyPropData;") == 0 then
  -- initial script run (but not when loaded from scene file!)
  MyPropData = {}
  MyPropData.MyItem = tcleval("set MyPropData(MyItem) 1.0;")
  tcleval("set MyPropData(SP) {MyItem};")
else
  -- all following script runs (and also when loaded from scene file!)
  MyPropData = {}
  MyPropData.MyItem = tcleval("set MyPropData(MyItem);")
end

if tcleval("info exists MyPropGUI;") == 0 then
  -- create property GUI "MyProp"
  tcleval("set ::phw [addPropertyGUI MyProp \"\" \"\"];")
  tcleval("addParam $::phw MyPropData MyItem;")
end

crtOb("Sphere")
sL()
getProp()
tclset("SphereAttrData(Radius)", MyPropData.MyItem)
tclset("SphereAttrData(ZMin)", -MyPropData.MyItem)
tclset("SphereAttrData(ZMax)", MyPropData.MyItem)
setProp()

This example demonstrates how to manage property data using the Lua object variable "MyPropData". The property data can be saved to and read from Ayam scene files with the help of a mirroring array variable on the Tcl side (also named "MyPropData"). To make this work properly, the initialisation of the Lua object must be constrained to the first script run: when the property data was read from a scene file, initialisation must not be run, instead the read data must be fetched from the Tcl context. This is what the first "if" statement, checking for existence of the mirroring Tcl array variable, in above example is all about.

Following this scheme of dual mirroring data structures on the Tcl and Lua sides, now the property GUI is created, which is also constrained to just one script run by a similar "if" statement.

After the GUI, a Sphere object is created and parameterised according to the data in the property GUI, which is used as radius, zmin, and zmax value.


Next Previous Contents