3.7. Fields within a Node

When you create a node, its fields are already set to predefined values. Afterward, you can change the values in its fields directly. The syntax for setting the value of a field depends on the type of the field and whether it is a single-value or multiple-value field. The following example creates a drawing-style node and sets its fields:

SoDrawStyle *d = new SoDrawStyle;
d->style.setValue(SoDrawStyle::LINES) ; 
d->lineWidth.setValue(3) ;
d->linePattern.setValue(0xf0f0);
  
SoDrawStyle d = new SoDrawStyle();
d.style.Value = SoDrawStyle.Styles.LINES ; 
d.lineWidth.Value = 3 ;
d.linePattern.Value = 0xf0f0;
  
SoDrawStyle d = new SoDrawStyle();
d.style.setValue(SoDrawStyle.Styles.LINES) ; 
d.lineWidth.setValue(3) ;
d.linePattern.setValue((short)0xf0f0);
  

The current drawing style is now nonfilled, dashed outlines, with a line width of 3 pixels. If you do not set the field values explicitly, Inventor uses the default values for that node. Default values for SoDrawStyle SoDrawStyle SoDrawStyle nodes are as follows:

Field

Default Values

style

SoDrawStyle::FILLED

lineWidth

1

linePattern

0xffff (solid)

pointSize 1

The following sections discuss setting and getting values for different types of fields. See also Chapter 15, Engines, which discusses field-to-field connections as well as several special types of fields—global fields and trigger fields.

You may be wondering why Inventor nodes have fields instead of simple member variables. This section outlines a few of the mechanisms provided by fields. The Inventor Toolmaker provides additional background on these topics.

First, fields provide consistent methods for setting and inquiring values, as described in the following sections and in the Open Inventor C++ Reference Manual. Second, fields provide a mechanism for Inventor to detect changes to the database. Third, you can connect fields in one node to fields in another node, as described in Chapter 15, Engines. Finally, fields provide a consistent and automatic way to read and write node values.

A single-value field has one value of a given type. Single-value fields include the letters SF in their class name. For example:

Single-value fields are used for nodes that have no use for arrays of values, such as a line pattern, a translation value, a rotation value, or a camera aspect ratio.

A multiple-value field contains an array of values. Multiple-value fields include the letters MF in their class name—for example, SoMFBool SoMFBool SoMFBool , SoMFFloat SoMFFloat SoMFFloat , SoMFVec3f SoMFVec3f SoMFVec3f , and SoMFColor SoMFColor SoMFColor . Multiple-value fields are used for coordinate points and normal vectors. They are also used for materials, so that you can assign different colors to different vertices. Most fields have both SF and MF forms. See the Open Inventor C++ Reference Manual for descriptions of fields within each node class.

The examples earlier in this chapter show how to declare and create nodes. This section provides additional examples of the syntax for setting and getting values for single-value fields within the nodes. (Most fields have a setValue() and getValue() method and can also use the = operator to set values.)

This first example sets the value in the height field of an SoOrthographicCamera SoOrthographicCamera SoOrthographicCamera node through use of the setValue() method. This field is of type SoSFFloat SoSFFloat SoSFFloat :

SoOrthographicCamera *cam = new SoOrthographicCamera;
cam->height.setValue(1.);
    
SoOrthographicCamera cam = new SoOrthographicCamera();
cam.height.Value = 1.0f;
    
SoOrthographicCamera cam = new SoOrthographicCamera();
cam.height.setValue(1f);
    

or

cam->height = 1.; // = operator has been defined for this field
    

To get the value for this field, use the getValue() method:

float result = cam->height.getValue();
    
float result = cam.height.Value;
  
float result = cam.height.getValue();
  

You can specify an SoSFVec3f SoSFVec3f SoSFVec3f field in several different formats. Each defines a 3D vector:

  • You can set it from a vector (an SbVec3f SbVec3f ).

  • You can set it from three floats (either a vector or three separate values).

  • You can set it from an array of three floats.

The following examples show how to set values for SoSFVec3f SoSFVec3f SoSFVec3f fields. An SoTransform SoTransform SoTransform node has a field, translation, which is an SoSFVec3f SoSFVec3f SoSFVec3f field that contains one value of type SbVec3f SbVec3f . The variable xform is a transform-node instance.

SoTransform *xform = new SoTransform;

//(1) Setting the field from a vector

SbVec3f vector;
vector.setValue(2.5, 3.5, 0.0);
xform->translation.setValue(vector);
// or: xform->translation = vector;


//(2a) Setting the field from a vector of three floats
 
xform->translation.setValue(SbVec3f(2.5, 3.5, 0.0));
// or: xform->translation = SbVec3f(2.5, 3.5, 0.0);


//(2b) Setting the field from three floats

float x = 2.5, y = 3.5, z = 0.0;
xform->translation.setValue(x, y, z);


//(3) Setting the field from an array of three floats

float floatArray[3];
floatArray[0] = 2.5;
floatArray[1] = 3.5;
floatArray[2] = 0.0;
xform->translation.setValue(floatArray);
      
SoTransform xform = new SoTransform();

//(1) Setting the field from a vector

SbVec3f vector = new SbVec3f();
vector.SetValue(2.5f, 3.5f, 0f);
xform.translation.Value = vector;


//(2a) Setting the field from a vector of three floats
 
xform.translation.Value = new SbVec3f(2.5f, 3.5f, 0f);


//(2b) Setting the field from three floats

float x = 2.5f, y = 3.5f, z = 0f;
xform.translation.SetValue(x, y, z);


//(3) Setting the field from an array of three floats

float[] floatArray = new float[3];
floatArray[0] = 2.5f;
floatArray[1] = 3.5f;
floatArray[2] = 0f;
xform.translation.SetValue(floatArray);
      
SoTransform xform = new SoTransform();

//(1) Setting the field from a vector

SbVec3f vector = new SbVec3f();
vector.setValue(2.5f, 3.5f, 0f);
xform.translation.setValue(vector);


//(2a) Setting the field from a vector of three floats
 
xform.translation.setValue(new SbVec3f(2.5f, 3.5f, 0f));


//(2b) Setting the field from three floats

float x = 2.5f, y = 3.5f, z = 0f;
xform.translation.setValue(x, y, z);


//(3) Setting the field from an array of three floats

float[] floatArray = new float[3];
floatArray[0] = 2.5f;
floatArray[1] = 3.5f;
floatArray[2] = 0f;
xform.translation.setValue(floatArray);
      

Use the getValue() method to get values for a field. This example copies the vector, changes it, and copies it back:

SbVec3f t = xform->translation.getValue();

t[0] += 1.0;
xform->translation.setValue(t);
// or: xform->translation = t;
      
SbVec3f t = xform.translation.Value;

t[0] += 1f;
xform.translation.Value = t;
    
SbVec3f t = xform.translation.getValue();

t.setValueAt(0, 1f);
xform.translation.setValue(t);
    

A rotation field specifies a rotation in 3D space. Since an SbRotation SbRotation represents rotation around an axis by an angle, you can set its value by specifying the axis and angle:

SbRotation r;
SbVec3f axis(0., 1., 0.);
float angle = M_PI; //from math.h
r.setValue(axis, angle);
// or SbRotation r(SbVec3f(0., 1., 1.), M_PI);
      
SbRotation r = new SbRotation();
SbVec3f axis = new SbVec3f(0f, 1f, 0f);
float angle = (float)Math.PI;
r.SetValue(axis, angle);
// or SbRotation r = new SbRotation(new SbVec3f(0f, 1f, 0f), (float)Math.PI);
      
SbRotation r = new SbRotation();
SbVec3f axis = new SbVec3f(0f, 1f, 0f);
float angle = (float)Math.PI;
r.setValue(axis, angle);
// or SbRotation r = new SbRotation(new SbVec3f(0f, 1f, 0f), (float)Math.PI);
      

You can also define a rotation to rotate one direction vector into another, as follows:

SbRotation r(SbVec3f(0.0, 0.0, 1.0), SbVec3f(0.0, 1.0, 0.0));
      
SbRotation r = new SbRotation(new SbVec3f(0f, 0f, 1f), new SbVec3f(0f, 1f, 0f));
      
SbRotation r = new SbRotation(new SbVec3f(0f, 0f, 1f), new SbVec3f(0f, 1f, 0f));
      

To set the value of the rotation field of an SoTransform SoTransform SoTransform node:

SoTransform *xform = new SoTransform;
xform ->rotation = r;
      
SoTransform xform = new SoTransform();
xform.rotation.Value = r;

      
SoTransform xform = new SoTransform();
xform.rotation.setValue(r);
      

You can also use setValue() to set the value of a rotation field and supply an axis and angle, a quaternion, or two vectors.

The = (assignment) operator can be used to set a field's value from another field of the same type. As with vectors, getValue() returns the value of the field.

[Tip]

Tip: If you want to specify a rotation as an axis/angle, you must pass an SbVec3f SbVec3f and a float. Passing four floats specifies a quaternion.

The SoMaterial SoMaterial SoMaterial node contains the following fields:

These examples show different styles for setting the fields of an SoMaterial SoMaterial SoMaterial node. The transparency field is of type SoMFFloat SoMFFloat SoMFFloat , so it contains one or more values of type float. The diffuseColor field is of type SoMFColor SoMFColor SoMFColor , so it contains one or more values of type SbColor SbColor . The syntax for setting multiple values in an SoMFFloat SoMFFloat SoMFFloat field is as follows:

nodeName->fieldName.setValues(starting index, number of values, pointer to array of values);
        
nodeName.fieldName.SetValues(starting index, array of values); 
        
nodeName.fieldName.setValues(starting index, array of values); 
       

For example:

SoMaterial *mtl;
float vals[3];
vals[0] = 0.2;
vals[1] = 0.5;
vals[2] = 0.9;
mtl->transparency.setValues(0, 3, vals);
        
SoMaterial mtl = new SoMaterial();
float[] vals = new float[3];
vals[0] = 0.2f;
vals[1] = 0.5f;
vals[2] = 0.9f;
mtl.transparency.SetValues(0, vals);
        
SoMaterial mtl = new SoMaterial();
float[] vals = new float[3];
vals[0] = 0.2f;
vals[1] = 0.5f;
vals[2] = 0.9f;
mtl.transparency.setValues(0, vals);
        

Space for the array is reallocated when necessary. The values are copied in from the array. An example of setting a multiple-value field that uses an Sb type is as follows:

SoMaterial *mtl;
SbVec3f vals[3];

vals[0].setValue(1.0, 0.0, 0.0);
vals[1].setValue(0.0, 1.0, 0.0);
vals[2].setValue(0.0, 0.0, 1.0);
mtl = new SoMaterial;
mtl->diffuseColor.setValues(0, 3, vals);
        
SoMaterial mtl = new SoMaterial();
SbColor[] vals = new SbColor[3];

vals[0].SetRGBValue(1f, 0f, 0f);
vals[1].SetRGBValue(0f, 1f, 0f);
vals[2].SetRGBValue(0f, 0f, 1f);
mtl.diffuseColor.SetValues(0, vals);
        
SoMaterial mtl = new SoMaterial();
SbColor[] vals = new SbColor[3];

vals[0].setValue(1f, 0f, 0f);
vals[1].setValue(0f, 1f, 0f);
vals[2].setValue(0f, 0f, 1f);
mtl.diffuseColor.setValues(0, vals);
        

If you want to set only one value in an SoMFFloat SoMFFloat SoMFFloat field, you can use the following shorthand method:

nodeName->fieldName.setValue(value1);
        
nodeName.fieldName.SetValue(value1);
        
nodeName.fieldName.setValue(value1);
        

For example:

mtl->transparency.setValue(.25); 
//or mtl->transparency = .25;

mtl.transparency.SetValue(.25f);
        
mtl.transparency.setValue(.25f);

This short method sets the number of values equal to 1 and sets the field to the specified value. However, it also throws away any subsequent values that were previously set in the array, so you should use it only to set the field to have one value. Use the longer method (setValues) or the set1Value() method if you want to change one value in the array and preserve the rest of the values.

You can use the [ ] operator to get a particular value within a multiple-value field as follows:

f = myMtl->transparency[13]; // get 14th value of array
        
f = myMtl.transparency[13]; // get 14th value of array
        
f = myMtl.transparency.getValueAt(13); // get 14th value of array
        

You can also create loops to access all values in the field:

for (i = 0; i < myMtl->transparency.getNum(); i++)
{
      printf("transparency value %d is %g\n", i, 
               myMtl->transparency[i]);
}
        
for (i = 0; i < myMtl.transparency.GetNum(); i++)
{
  Console.WriteLine("transparency value {0} is {1}", i, 
                    myMtl.transparency[i]);
}
        
for (i = 0; i < myMtl.transparency.getNum(); i++)
{
  System.out.println("transparency value " + i + " is " +
                     myMtl.transparency.getValueAt(i));
}
        

To insert values in the middle of a field:

float newValues[2];
newValues[0] = 0.1;
newValues[1] = 0.2;

// First, make space; after this, myMtl->transparency[10] 
// and myMtl->transparency[11] will have arbitrary values:

myMtl->transparency.insertSpace(10, 2);

// Set the space created to the right values:

myMtl->transparency.setValues(10, 2, newValues);
        
float[] newValues = new float[2];
newValues[0] = 0.1f;
newValues[1] = 0.2f;

// First, make space; after this, myMtl.transparency[10] 
// and myMtl.transparency[11] will have default values:

myMtl.transparency.InsertSpace(10, 2);

// Set the space created to the right values:

myMtl.transparency.SetValues(10, newValues);
        
float[] newValues = new float[2];
newValues[0] = 0.1f;
newValues[1] = 0.2f;

// First, make space; after this, myMtl.transparency[10] 
// and myMtl.transparency[11] will have default values:

myMtl.transparency.insertSpace(10, 2);

// Set the space created to the right values:

myMtl.transparency.setValues(10, newValues);
        

To delete values from a field:

// Delete myMtl->transparency[8] and myMtl->transparency[9];
// the values in myMtl->transparency[10] on up will be moved
// down to fill in the missing space, and the transparency
// array will have two fewer values.

myMtl->transparency.deleteValues(8, 2);
        
// Delete myMtl.transparency[8] and myMtl.transparency[9];
// the values in myMtl.transparency[10] on up will be moved
// down to fill in the missing space, and the transparency
// array will have two fewer values.

myMtl.transparency.DeleteValues(8, 2);
        
// Delete myMtl.transparency[8] and myMtl.transparency[9];
// the values in myMtl.transparency[10] on up will be moved
// down to fill in the missing space, and the transparency
// array will have two fewer values.

myMtl.transparency.deleteValues(8, 2);
        

See the Open Inventor C++ Reference Manual for additional methods used to edit MF fields.

Every field has an Ignore flag associated with it. Use the setIgnored() method to set or reset the Ignore flag. When this flag is set, the field is disregarded. This flag enables you to ignore certain fields in a node and to use others. For example, to ignore the specular color field in a material node so the value is inherited from the previous material:

SoMaterial *bronze = new SoMaterial;

bronze->ambientColor.setValue(.33, .22, .27);
bronze->diffuseColor.setValue(.78, .57, .11);
bronze->specularColor.setIgnored(TRUE);
bronze->shininess = .28;
          
SoMaterial bronze = new SoMaterial();

bronze.ambientColor.SetValue(.33f, .22f, .27f);
bronze.diffuseColor.SetValue(.78f, .57f, .11f);
bronze.specularColor.SetIgnored(true);
bronze.shininess.SetValue(.28f);
          
SoMaterial bronze = new SoMaterial();

bronze.ambientColor.setValue(.33f, .22f, .27f);
bronze.diffuseColor.setValue(.78f, .57f, .11f);
bronze.specularColor.setIgnored(true);
bronze.shininess.setValue(.28f);
          

To turn the Ignore flag off:

bronze->specularColor.setIgnored(FALSE);
          
bronze.specularColor.SetIgnored(false);
          
bronze.specularColor.setIgnored(false);
          

The isIgnored() method returns TRUE if the Ignore flag for this field is set:

if (bronze->specularColor.isIgnored()) {
   printf("Yes, specular is ignored\n");
}
          
if (bronze.specularColor.IsIgnored())
{
  Console.WriteLine("Yes, specular is ignored");
}
          
if (bronze.specularColor.isIgnored())
{
  System.out.println("Yes, specular is ignored");
}
          

Some fields are not inherited and are thus not affected by the Ignore flag. Examples of fields that are not inherited are the fields of shape nodes, light-source nodes, some groups, and cameras, as well as the fields in the SoEnvironment SoEnvironment SoEnvironment node. If you set the Ignore flag for a field whose values are not inherited, Inventor simply uses the field's default values.