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:


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

.NET
SoDrawStyle d = new SoDrawStyle();
d.style.Value = SoDrawStyle.Styles.LINES ; 
d.lineWidth.Value = 3 ;
d.linePattern.Value = 0xf0f0;
  

Java
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( C++ | Java | .NET ) 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( C++ | Java | .NET ), SoMFFloat( C++ | Java | .NET ), SoMFVec3f( C++ | Java | .NET ), and SoMFColor( C++ | Java | .NET ). 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( C++ | Java | .NET ) node through use of the setValue() method. This field is of type SoSFFloat( C++ | Java | .NET ):


C++
SoOrthographicCamera *cam = new SoOrthographicCamera;
cam->height.setValue(1.);
    

.NET
SoOrthographicCamera cam = new SoOrthographicCamera();
cam.height.Value = 1.0f;
    

Java
SoOrthographicCamera cam = new SoOrthographicCamera();
cam.height.setValue(1f);
    

or


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

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


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

.NET
float result = cam.height.Value;
  

Java
float result = cam.height.getValue();
  

You can specify an SoSFVec3f( C++ | Java | .NET ) field in several different formats. Each defines a 3D vector:

  • You can set it from a vector (an SbVec3f( C++ | Java )).

  • 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( C++ | Java | .NET ) fields. An SoTransform( C++ | Java | .NET ) node has a field, translation, which is an SoSFVec3f( C++ | Java | .NET ) field that contains one value of type SbVec3f( C++ | Java ). The variable xform is a transform-node instance.


C++
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);
      

.NET
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);
      

Java
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:


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

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

.NET
SbVec3f t = xform.translation.Value;

t[0] += 1f;
xform.translation.Value = t;
    

Java
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( C++ | Java ) represents rotation around an axis by an angle, you can set its value by specifying the axis and angle:


C++
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);
      

.NET
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);
      

Java
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:


C++
SbRotation r(SbVec3f(0.0, 0.0, 1.0), SbVec3f(0.0, 1.0, 0.0));
      

.NET
SbRotation r = new SbRotation(new SbVec3f(0f, 0f, 1f), new SbVec3f(0f, 1f, 0f));
      

Java
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( C++ | Java | .NET ) node:


C++
SoTransform *xform = new SoTransform;
xform ->rotation = r;
      

.NET
SoTransform xform = new SoTransform();
xform.rotation.Value = r;

      

Java
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( C++ | Java ) and a float. Passing four floats specifies a quaternion.

The SoMaterial( C++ | Java | .NET ) node contains the following fields:

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


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

.NET
nodeName.fieldName.SetValues(starting index, array of values); 
        

Java
nodeName.fieldName.setValues(starting index, array of values); 
       

For example:


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

.NET
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);
        

Java
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:


C++
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);
        

.NET
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);
        

Java
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( C++ | Java | .NET ) field, you can use the following shorthand method:


C++
nodeName->fieldName.setValue(value1);
        

.NET
nodeName.fieldName.SetValue(value1);
        

Java
nodeName.fieldName.setValue(value1);
        

For example:


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


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

Java
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:


C++
f = myMtl->transparency[13]; // get 14th value of array
        

.NET
f = myMtl.transparency[13]; // get 14th value of array
        

Java
f = myMtl.transparency.getValueAt(13); // get 14th value of array
        

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


C++
for (i = 0; i < myMtl->transparency.getNum(); i++)
{
      printf("transparency value %d is %g\n", i, 
               myMtl->transparency[i]);
}
        

.NET
for (i = 0; i < myMtl.transparency.GetNum(); i++)
{
  Console.WriteLine("transparency value {0} is {1}", i, 
                    myMtl.transparency[i]);
}
        

Java
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:


C++
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);
        

.NET
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);
        

Java
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:


C++
// 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);
        

.NET
// 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);
        

Java
// 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:


C++
SoMaterial *bronze = new SoMaterial;

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

.NET
SoMaterial bronze = new SoMaterial();

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

Java
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:


C++
bronze->specularColor.setIgnored(FALSE);
          

.NET
bronze.specularColor.SetIgnored(false);
          

Java
bronze.specularColor.setIgnored(false);
          

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


C++
if (bronze->specularColor.isIgnored()) {
   printf("Yes, specular is ignored\n");
}
          

.NET
if (bronze.specularColor.IsIgnored())
{
  Console.WriteLine("Yes, specular is ignored");
}
          

Java
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( C++ | Java | .NET ) node. If you set the Ignore flag for a field whose values are not inherited, Inventor simply uses the field's default values.