© Copyright 1996, ModelWorks Software
What is Express? Express is a VRML preprocessor that lets you write VRML with expressions to generate VRML In Express almost all VRML field values can be defined using general expressions. For example in Express you can write:
orientation =PointAt(10,5,0) # Points the camera at (10,5,0) from the camera's position
rather than having to figure out what the rotation parameters should be. Expressions can use the usual arithmithic operators (e.g., +,-,*,/), conversion operators (e.g., 45'deg), fields names as variables, and many built-in functions. Expressions can define scalar, vector or matrix values.
Express also includes a number of specialized statements and nodes, such as INCLUDE and LOOP lets you write general programs using Express to generate VRML.
If you are new to VRML or 3D graphics
Table of Contents
Figure 1 shows the main window of Express. It consists of an edit pane
and a message pane. The upper panel is the editor and the lower panel displays
messages generated while building a VRML world file. To build a world file
use the Build command from the Express menu. Use the Insert and Function
menu to insert templates into your file.
Figure 1. Express window.
For example, to build a simple world do the following:
The resulting Express code - which is also legal VRML in this case - should look like this:
#VRML V1.0 ascii Separator { # Options: ON OFF AUTO renderCulling AUTO Cone { parts ALL bottomRadius 1 height 1 } }
Next, choose Build from the Express menu. This will create a world file
"Output.wrl" in your default directory.
Most of the examples discussed in this document are include the Examples folder inside your Express folder. Both Express and world files are included. A few of the examples do not work well in all browsers. Drive.wrl should be driven using WebFX. Stars.wrl should be viewed using VRScout.
Express programs use a general expression together with special nodes and statements. Express programs can be as simple as using expressions to define values of fields or can be as complex as using loops, conditional statements and parameter based objects.
To use an expression in Express just enter an expression in place of a VRML field value. In the following example the orientation field is defined by the Express function pointAt and the heightAngle is defined an Express unit conversion expression.
PerspectiveCamera { position -10 5 10 orientation =PointAt(0,5,0) # Points the camera at (0,5,0) from (-10,5,10) heightAngle 45'deg # Converts 45 degrees to radians }
You can also use the values of other fields in an expression. If the field you want to use is in the current node or in a parent of the current node you can just use the name the field in the expression. If the field you want to use is not in the path of the current node or there is more than one field using the same name in the path you can refer to the field using the nodeName ':' fieldName. For example the first value of the translation field defined below is given the value of the loop's position field.
LOOP { fields [SFFloat start, SFFloat end, SFFloat position, SFFloat step] start 0 end 5 Translation { translation position 0 0 # The first element of the translation field is set to the } # the value of the LOOP's position field }
See operators and functions for more information.
One of the easiest programs to write in Express is to use a loop to place objects in a world. The following simple example places 6 Spheres on the y-axis. By changing the start and end values you can easily generate more or fewer objects. By changing the translation field you can place the objects in different locations. Example files: Loop.vxr and Loop.wrl
LOOP { fields [SFFloat start, SFFloat end, SFFloat position, SFFloat step] start -3 end 4 Separator { Translation { translation 0 position 0 } Sphere { radius .5 } } }
The next example lays out the columns for a "greek" temple. Here we use a double loop together with an INCLUDE for the definition of the column. The SELECT is used to include the column only once. From then on a USE statement is used to reference the definition of the greekColumn. Note the use of a conditional expression to compute whichChild.
DEF xAxis LOOP { fields [SFFloat start, SFFloat end, SFFloat position, SFFloat step] start 0 end 5 DEF zAxis LOOP { fields [SFFloat start, SFFloat end, SFFloat position, SFFloat step] start 0 end 5 Separator { Translation { translation xAxis:position 0 zAxis:position } SELECT { fields [ SFLong whichChild ] whichChild if(xAxis:position==0&&zAxis:position==0)then(0)else(1) INCLUDE Column.vxr # Include greekColumn definition only once USE greekColumn # Use a reference the rest of the time } } } }
Example files: Greek.vxr, Drive.vxr and SpiralStairs.vxr
This example defines the points for a triangle located on the x-axis and then reflects the triangle across the x = 0 plane. The APPEND statement does most of the work. Its job is to apply the transformation matrix to the triangle data and then to append the results to the to the original triangle data. In 3D graphics we apply a transformation by multiplying the data by the transformation matrix. But before we can multiply we must first convert the 3D data to 4D homogeneous coordinates, then multiply 4D data points by the matrix, and then convert the results back to 3D (It's easier to do in Express than to say it!). The result of this program will be a Coordinate3 object with two triangles, each a mirror image of the other. Example files: Reflect.vxr. Reflect.wrl. Matrix.vxr and Matrix.wrl.
DEF object Coordinate3 { point [1 0 0, 2 0 0, 2 1 0 ] # MFVec3f } APPEND object:point convert3D(convert4D(object:point)*yzReflect())
The next example generates the data for a 10 by 10 meter grid on the plane y = 0. It uses the APPEND statement together with a loop to generate the grid.. Each time through the loop we generate one grid line parallel to the x-axis and another grid line parallel to the z-axis. Since the loop is repeated 10 times, this results in a 10 by 10 grid. Example files: Grix.vxr and Grid.wrl
# This is where we will put the grid data DEF gridData Coordinate3 { point [] # MFVec3f } # This is where we will put the polyline indexes DEF grid IndexedLineSet { coordIndex [] # MFLong } LOOP { fields [SFFloat start, SFFloat end, SFFloat step, SFFloat position ] start 0 end 10+1 step 1 # Generate the grid points APPEND gridData:point (0,0,position) APPEND gridData:point (10,0,position) APPEND gridData:point (position,0,0) APPEND gridData:point (position,0,10) # Generate the polyline indexes APPEND grid:coordIndex (position-start)*4 APPEND grid:coordIndex (position-start)*4+1 APPEND grid:coordIndex -1 # end this polyline APPEND grid:coordIndex (position-start)*4+2 APPEND grid:coordIndex (position-start)*4+3 APPEND grid:coordIndex -1 # end this polyline }
Using parameter based objects is a way to speed up writing VRML and also helps you to organize your world. For example suppose that you want display an x-z grid in your world as a debugging aid. You could create a grid using the Express program described above, or you could INCLUDE a parameter based object. The file gridXZ.vxr is a parameter based object that lets you define its grid parameters. It can be used like this:
PARAMETERS { # These are the parameters you will "pass" to gridXZ.vxr fields [SFFloat fromX, SFFloat toX, SFFloat fromZ, SFFloat toZ, SFFloat gridSpacing] fromX -10 toX 10 fromZ 0 toZ 10 gridSpacing .5 INCLUDE gridXZ.vxr }
To build a parameter based object you write a program that uses inherited fields in its expressions and save it in an Express file. Example files: GridXZ.vxr and StreetLight.vxr.
If you are building world files using multiple tools you may want to use Express to automate the integration of these files. For example to build a simple Express program to integrate two world files do the following:
#VRML V1.0 ascii Separator { # Options: ON OFF AUTO renderCulling AUTO Separator { Transform { # set transform fields as appropriate } INCLUDE file1.wrl } Separator { Transform { # set transform fields as appropriate } INCLUDE file2.wrl } OUTPUT_TO integratedFile.wrl }
The language used by Express is a superset of VRML. A VRML 1.0 file is legal input for Express 1.0. However the converse is not necessarily true. The reason for this is that Express allows general symbolic expressions for most field values and also includes new statements.
The ability to use expressions to define value and to refer to values of fields is a key part of Express. Express allows the values of most VRML fields to be specified using an expression. Fields which cannot be defined using an expression are SFEnum, SFBitMask and SFImage.
Express expression syntax provides much of the capability of expressions that are provided in other languages. For detailed descriptions see the grammar and operator reference sections included in this document.
However because VRML uses spaces to separate values in fields, expressions must be written without spaces. For example:
(sqrt(x*x+y*y)) # is legal (sqrt(x*x + y*y)) # is illegal
Normally, Express reads an expression for each element of a field. However, reading a field element by element does not let a user use a function or expression that can define a field. To solve this problem Express uses an '=' character at the start of an expression to indicate the following expression is a field expression.
Examples:
MatrixTransform { matrix =YRotate(45'deg) # This function computes the 4x4 transform matrix for a 45 deg rotation #about the Y axis } DEF data Coordinate3 { point[1 0 1, 0 1 1, 1 1 0] } Coordinate3 { point =data:point # Defines the point field using a value from the data node above } DEF colorData PARAMETERS { fields [MFColor color ] color [ =Color("red"), =Color("blue"),=Color("green") ] # The Color function returns a SFVec3f value } Material { ambientColor [ =colorData:color, 0 0 0 ] # MFColor }
To define a vector from scalar values you enclose a list of scalars in parenthesis. Examples
(0,0,0) # Defines a SFVec3f ((1,0,0,0);(0,1,0,0);(0,0,1,0);(0,0,0,1)) # Defines the 4x4 Identity matrix
NOTE: You should be aware that operations on matrixes and vectors don't quite follow the rules of scalar operations (e.g., 4+7). Only certain operations on vectors and matrixes are defined. You can add and subtract vectors and matrixes so long as their dimensions are the same. You can multiply a vector and a matrix provided that the number of columns of the vector is equal to the number of rows of the matrix. You can also multiply two matrixes provided that the number of columns of the first matrix is equal to the number of rows of the second matrix..
You can use "VARNAME" in place of the VRML "DEF" keyword to define the name of a node using an expression. The syntax of VARNAME is:
VARNAME nodeName NODECLASS
where nodeName is of the form name~`expr1`~`expr2`…. This expression concatenates name with the ASCII integer value of expr1 and expr2. For example: ball~`expr1`~`expr2` creates the names ball23 if expr1 evaluates to 2 and expr2 evaluates to 3. You can also use this form of nodeName in a USE statement.
See the Lattice.vxr file for an example of how to use VARNAME
Express uses nodes to implement operations that are performed when you build a world file. In general, these nodes are not copied to world files and produce no output of their own. However if you include VRML nodes as children they will be copied to the world file. Express nodes are specified like the VRML Unknown Node - that is they require a fields […] definition after the bracket.
This release of Express includes the following nodes:
PARAMETERS { fields [ <field type> <field name>] # set field values as required # note that it is not necessary to set the value of fields if # they are set before they are used }
Example:
DEF parameters PARAMETERS { fields [ SFFloat param ] param 10 # The value of param is set to 10 # To use the value of param later refer to it as "parameters:param" # If this node is a parent then you can refer to # the value as "param" and let # Express finds the value using inheritance }
LOOP node. The LOOP node lets you repeat a group
of nodes. Its syntax is:
LOOP { fields [SFFloat start, SFFloat end, SFFloat position, SFFloat step] start <expression> end <expression> step <expression> # Nodes included here will be executed each time the loop is repeated }
The loop is repeated for start to end by step while position is less than end. The default value of step is 1. The field position contains the current value of the loop as it goes from start to end by step.
The following example places 7 spheres along the y axis from x equal -3 to x equal 3 The value of position in the translation field is determined using inheritance.
LOOP { fields [SFFloat start, SFFloat end, SFFloat position, SFFloat step] start -3 end 4 Separator { Translation { translation position 0 0 } Sphere { radius .5 } } }
SELECT node. This node uses the same syntax as the VRML Switch node. Its syntax is:
SELECT { fields [ SFLong whichChild ] whichChild <expression> <child node #0> <child node #n-2> <child node #n-1> }
This node evaluates one, none, or all of its children. The whichChild
field specifies the index of the child to traverse, where the first child
has index 0. A value of -1 (the default) means do not evaluate any children.
A value of -3 evaluates all the children.
The following example places 7 objects along the y axis from x equals
-3 to x equals 3. If abs(position mod 2) is 0 then the Cube will be generated,
if abs(position mod 2) is 1 then the Sphere will be generated
LOOP { fields [SFFloat start, SFFloat end, SFFloat position, SFFloat step] start -3 end 4 SELECT { fields [ SFLong whichChild ] whichChild abs(position%2) Separator { Translation { translation position 0 0 } Cube { width .5 height .5 depth .5 } } Separator { Translation { translation position 0 0 } Sphere { radius .5 } } } }
APPEND. This statement lets you append a value to a MF field. The syntax is:
APPEND nodeName:fieldName value
The value may be one or more complete elements for a MF field. Note that you cannot append to part of field.
Examples:
DEF data Coordinate3 { point[] } APPEND data:point (1,1,1) # Add one point APPEND data:point ((1,1,1),(0,0,0),(1,1,0)) # Add three points APPEND data:point 1 # Illegal - point requires three values
DECLARE nodeName:fieldName value
If value is a scalar then that value is used to pre-allocate fields for the specified MFField. If value is a vector then the first element is used to pre-allocate fields and the second element is the grow factor. The default grow factor for MFFields is 10
Examples:
DECLARE node:color 256 # Allocates 256 fields for the MFColor field DECLARE node:point (400,50) # Allocates 400 fields and sets the grow factor to 50
OUTPUT_TO. This statement lets you change the default output file. Its syntax is:
OUTPUT_TO fileName.wrl
Examples:
OUTPUT_TO Cone.wrl OUTPUT_TO "Release/Cone.wrl"
PRECISION value
Value may be any scalar expression. Generally the value should be some power of 10 such as 10, 1, 0.1, 0.01.
Example:
PRECISION .0001 # This is the default
PRINT expression
Example:
PRINT position # Will output "Line nn: position is X"
SET. This statement lets you set the value of fields in other nodes. The syntax for this node is:
SET nodeName:fieldName value
Value may be any legal expression. This includes a whole field or some part of a field.
Examples:
SET node:point (1,1) # Sets the value of a SFVec2f SET node:color[1][2] .5 # Sets the blue value of the second field of a MFColor SET node:point data:point # Sets the value of node:point to the value of field data:point
This release of Express contains three generator nodes. Generator nodes are high level nodes used to describe a graphical object from a minimum amount of data. More generators will be added in future releases.
The Ball node is a simple generator that lets you place a sphere at a given location by just specifying the center field. Is syntax is:
Ball { fields [ SFVec3f center, SFFloat radius ] center 0 0 0 radius 1 }
Use this node with the Connect node described below. You can use this node to build a ball and stick chemical model. Example files: Connect.vxr, Lattice.vxr
The Connect node lets you connect two nodes together with a cylinder. Is syntax is:
Connect { fields [ SFNode first, SFNode second, SFFloat radius ] first nodeName # Name of a node with a SFVect3f center field second nodeName # Name of another node with a SFVect3f center field radius 1'cm }
Use this node with the Ball node described above. Example files: Connect.vxr , Lattice.vxr
The Wall node lets you describe a wall in terms width, its elevation, its height, and its inside or outside x-z coordinates. The Wall node uses the height and elevation field to locate the wall in the vertical direction. If there are more data elements than height or elevation elements, the Wall node will use the last height or elevation element. Its syntax is:
Wall { fields [ SFLong placement, SFFloat width, MFFloat height, MFFloat elevation, MFVec2f data ] placement 1 # -1: Inside, 1: Outside width 6'in height [ 8'ft ] elevation [ 0 ] data [] # Describe the (x,y) coordinates of the wall here }
Examples:
Wall { fields [ SFLong placement, SFFloat width, MFFloat height, MFFloat elevation, MFVec2f data] placement -1 width 8'in height [ 8'ft ] elevation [0] data [ 0 0, 2 0, 4 0, 4 2, 8 2, 8 4, 8 6, 0 6, 0 4, 0 2, 0 0 ] }
Example files: Walls.vxr, Drive.vxr
The Edit menu contains the standard edit items along with commands for indenting, commenting and reformating VRML. To indent or unindent a block of code select the block of code and choose indent or unindent. You can also use the tab key and the shift-tab keys to indent and unindent. The comment and uncomment can be used to comment and uncomment a block of code. The comment insert the VRML comment character '#' at the beginning of each line of code each time you use comment. Uncomment removes the first comment character at the beginning of each line of code. Reformat indents a whole file according the level of each node.
Use the build command in the Express menu to generate a world file. Any errors detected or messages generated while Express is building your VRML file will be displayed in the message pane at the bottom the Express window. When you click on a message, Express high-lights and shows the corresponding VRML source related to the message.
By default Express places the output generated by the build command in the file "Output.wrl" in the current directory. To change the default use the OUTPUT_TO statement.
Note: Express always saves your file before building the world file. If the file you are compiling has not been saved before, Express will prompt you for a file name. This file will be saved as a .vxr file (Express file). If you are compiling a .wrl file, Express will also prompt you for a file name and will save the original file as a .vxr file before compiling.
The view menu contains commands that let set the font and tab size. To set these attributes click on the appropriate pane and then choose an attribute to set from the View menu.
The Insert menu contains Express and VRML templates. This make it easy to insert code without having to remember, look up or type the syntax for Express or VRML
The function menu contains a list of all the built-in functions in Express. As with the Insert menu, selecting a function will insert the function template into your file.
Most error messages should be easy to understand. However you may need
some help with the message "Syntax error: found token - expecting
token or token,…". To interpret syntax error message, first click
on the error message to find out where the error occurred, then use the
grammar to interpret the error. For example
suppose you used the statement: "SET index 1". This
statement will generate a error message of the form "Syntax error
found NUMBER - expecting ':' or '~'". Since the error occurred
in a SET statement look up the syntax for the SET statement in the grammar.
There you will find that Express is expecting a "nodeName:fieldName
expr" for a simple SET statement. In this case the error message
is telling you that Express found the expr (the NUMBER token) but was expecting
a ':' followed by a fieldName which it did not find.
Constants e e() Return the constant e (2.718281828459045) pi pi() Returns the constant pi (3.141592653589793) General Math abs, fabs abs(x), fabs(x) Computes the absolute value of x arc cosine acos(x) Computes the arc cosine of x arc sine asin(x) Computes the arc sine of x arc tangent atan(x) Computes the arc tangent of x atan2(x, y) Calculates the arctangent of y/x. Atan2 returns a value in the range of -pi/2 to pi/2. If x or x and y are zero then atan2 returns 0. ceiling ceil(x) Rounds the x to the next integer. cosine cos(x) Computes the cosine of x distance dist(x1, y1, x2, y2), dist(x1, y1, z1, x2, y2, z2), dist(point, point) Computes the Euclidean distance between two points exp exp(x) Computes the e raised to x floor floor(x) Truncates the x to its integer part. float modulus fmod(x, y) Returns the remainder of x/y. This is same as x % y. hyperbolic cosine cosh(x) Computes the hyperbolic cosine of x hyperbolic sine sinh(x) Computes the hyperbolic sine of x hyperbolic tangent tanh(x) Computes the hyperbolic tangent of x hypotenuse hypot(x, y) Returns the square root of x*x + y*y. interpolate interpolate (point, point, amount), interpolate (x, y, amount) Returns the interpolated value between two points. Amount should be between 0 and 1. log log(x) Computes the log base e of x log10 log10(x) Computes the log base 10 of x maximum max(x, y) Returns the maximum of x and y. minimum min(x, y) Returns the minimum of x and y. power pow(x, y) Returns the x raised to y. This is same as x^y. rand rand() Returns a random number between 0.0 and 1.0 round round(x, precision) Rounds x to precision sine sin(x) Computes the sine of x. square root sqrt(x) Computes the square root of the s. X must be greater than or equal to 0.0. tangent tan(x) Computes the tangent of x. Special functions pointAt pointAt(x,y,x), pointAt(point) Computes the orientation value for the camera. Returns a SFRotation value. A position field must be defined in the same node in order for these versions of the function to work. pointAt(fromPoint,toPoint) Same as above but can be used to set any SFRotation field Note: Both PointAt functions assume that the rotation is to be computed from the vector going from (0,0,1) to (0,0,0) rotate rotate(x1,y1,z1,x2,y2,z2,x3,y3,z3,x4,y4,z4) rotate(point1,point2,point3,point4) rotate(fromDirection,toDirection) Like pointAt above, rotate computes a SFRotation field, but rotate lets you define the fromVector and the toVector The first two points define the fromVector and the third and fourth define the toVector. The third form assumes that each point is a unit vector FractalSurfaceData FractalSurfaceData(rows, cols, roughness, predefined) FractalSurfaceIndex FractalSurfaceIndex(rows, cols) These two functions are used together to generate the data for a fractal surface. The rows and cols parameters determine the size of the surface in meters. For now the number of rows and cols should be equal. The neutral value of roughness is 1.0. Values greater than one make the surface rougher. The predefined parameter is a MFFloat value. The first element specifies the height of the surface in the center. The next four elements specify the height for the midpoints from the center. Additional points are applied recursively until all the predefined values are used. Matrix functions determinate determinate(matrix) Computes the determinate of a square matrix inverse inverse(matrix) Computes the inverse of a square matrix transpose transpose(vector), transpose(matrix) Returns a transpose matrix Homogeneous coordinates convert4D convert4D(vector) convert4D(matrix) Converts a Nx3 array to a Nx4 homogeneous array convert3D convert3D(vector), convert3D(matrix) Converts a Nx4 homogeneous array to a Nx3 array Transformation matrix operations All these operations return a 4x4 transformation matrix translate translate(x,y,z) Generates the 4x4 transformation matrix to translate points by x,y,z. scale scale(overall) Generates the 4x4 transformation matrix to scale points by amount overall. scale scale(x,y,z); Generates the 4x4 transformation matrix to scale points by x,y,z. xyReflect xyReflect() Generates the 4x4 transformation matrix to reflect points across the z = 0 plane. yzReflect yzReflect() Generates the 4x4 transformation matrix to reflect points across the x = 0 plane. xzReflect xzReflect() Generates the 4x4 transformation matrix to reflect points across the y = 0 plane. xRotate xRotate(angle) Generates the 4x4 transformation matrix to rotate points around the x-axis by angle. yRotate yRotate(angle) Generates the 4x4 transformation matrix to rotate points around the y-axis by angle. zRotate zRotate(angle) Generates the 4x4 transformation matrix to rotate points around the z-axis by angle. rotate rotate(vector,vector,angle) Generates the 4x4 transformation matrix to rotate points around the line specified by the two vectors by angle. Color Functions color color(name) Returns a predefined color by name. The following colors are predefined red, green, blue, yellow, cyan, magenta, black, white, gray, lightGray, darkGray grayColor grayColor(amount) Returns a gray color with density equal to amount. Amount should be between 0 (white) and 1 (black). Note: You can use interpolate to get other colors (e.g., interpolate(color("red"),color("green"),.25))
Operator Notation Precedence (from low to high) comma x, x from left to right conditional if(x)then(y)else(z) from right to left NOTE: the parenthesis are required logical or x || y from left to right logical and x && y equal x == y from left to right not equal x != y > less than or equal x <= y less than x < y greater than or equal x >=y greater than x > y add x + y from left to right subtract x - y multiply x * y from left to right divide x / y remainder x % y power x ^ y from right to left unary logical not !x from right to left unary plus + x from right to left unary minus - y select field nodeName:fieldName from right to left :fieldName inherited only fieldName local and inherited subscript fieldName [index] from left to right fieldName [index] [index] grouping (x + y) * z from left to right array ((x1,y1);(x2,y2)) unit conversion x ' unit name from left to right inch x ' in converts to meters foot x ' ft converts to meters yard x ' yd converts to meters centimeter x ' cm converts to meters degree x ' deg converts to radians gradient x ' grad converts to radians
statement : expr | = expr | USE stringExpr | STRING stringExpr | DECLARE stringExpr : stringExpr expr | SET stringExpr : stringExpr expr { | SET stringExpr : stringExpr [ expr ] expr | SET stringExpr : stringExpr [ expr ] [ expr ] expr | APPEND stringExpr : stringExpr expr ; expr : factor | + expr | - expr | expr + expr // Addition operator | expr - expr // Subtraction operator | expr * expr // Multiplication operator | expr / expr // Division operator | expr % expr // Remainder operator | expr ^ expr // Power operator | ! expr // Logical NOT operator | expr && expr // Logical AND operator | expr || expr // Logical OR operator | expr == expr // Equal operator | expr != expr // Not equal operator | expr < expr // Less than operator | expr > expr // Greater than operator | expr <= expr // Less than or equal operator | expr >= expr // Greater than or equal operator | expr ' NAME // Conversion operator | if expr then expr else expr // Conditional operator ; factor : NUMBER | TRUE | FALSE | stringExpr ( ) // Function call | stringExpr ( exprList ) // Function call | fieldReference | fieldReference [ expr ] // row or element reference | fieldReference [ expr ] [ expr ] // element reference | cfactor ; fieldReference : stringExpr // Local and inherited field reference | : stringExpr // Inherited field reference | stringExpr : stringExpr // Node field reference ; stringExpr : NAME | stringExpr ~ stringExpr // String concatenation | stringExpr ~ ` expr ` // String concatenation and evaluation ; exprList : expr | exprList , expr // element separator ; cfactor : ( exprList ) // Grouping * | cfactor; ( exprList ) // row separator ** ; * Generates a scalar if only one element is in exprList Generates a vector if more than one element is in exprList ** Generates a matrix if more than one row is in cfactor