Trying and failing to set DataArray2D with JScript

First, let’s use Python to set up two ICE attributes with DataArray2D.

si = Application
from win32com.client import constants as C            # win32com.client.constants

oObj = si.Selection(0)
a = oObj.ActivePrimitive.AddICEAttribute("MyString", C.siICENodeDataString, C.siICENodeStructureArray, C.siICENodeContextSingleton)
a.DataArray2D = [["a", "b", "c", "d", "e"]]

a1 = oObj.ActivePrimitive.AddICEAttribute("MyString2", C.siICENodeDataString, C.siICENodeStructureArray, C.siICENodeContextSingleton)
a1.DataArray2D = [["u", "v", "w" ]]

Now, let’s try to set DataArray2D with JScript. As a reminder, here’s how you access the DataArray2D in JScript:

o = Selection(0);
a = o.ActivePrimitive.ICEAttributes("MyString");
x = VBArray( a.DataArray2D ).toArray();
LogMessage( VBArray( x[0] ).toArray() );
// INFO : a,b,c,d,e

Seeing that, you would think that you could set DataArray2D using an array of arrays or maybe an array, but no:

a.DataArray2D =  [[ "a", "b", "c" ]];
// WARNING : 3390 - This ICEAttribute doesn't refer to a 2D array: <Attribute: MyString2>

a.DataArray2D =  [ "a", "b", "c" ];
// WARNING : 3392 - Invalid offset specified while extracting data from this attribute: <Attribute: MyString2>
// <Offset: 110348408>

At this point, I started wondering if there was anyway at all to do it, so I tried to put back the same value:

a.DataArray2D = a.DataArray2D;
// WARNING : 3393 - The input array doesn't match this attribute's data type or structure type: <Attribute: MyString2>

Ack. Maybe if I converted it to a JScript array…well, at least something finally worked:

a.DataArray2D = VBArray( a.DataArray2D ).toArray();

Copying the DataArray2D from another attribute works too:

a = o.ActivePrimitive.ICEAttributes("MyString");
a1 = o.ActivePrimitive.ICEAttributes("MyString2");
a.DataArray2D = VBArray( a1.DataArray2D ).toArray();

So, based on that, I thought maybe I needed a safearray and things started getting a little hacky:

sa = getSafeArray( [ "a", "b", "c" ] );
jsa = new VBArray( sa ).toArray();

a.DataArray2D = sa;
// WARNING : 3392 - Invalid offset specified while extracting data from this attribute: <Attribute: MyString2>
// <Offset: 110348408>

a.DataArray2D = jsa;
// WARNING : 3392 - Invalid offset specified while extracting data from this attribute: <Attribute: MyString2>
// <Offset: 110348408>

// Get a safearray from a JScript array
function getSafeArray(jsArr) {
    var dict = new ActiveXObject("Scripting.Dictionary");
    for (var i = 0; i < jsArr.length; i++)
    dict.add(i, jsArr[i]);
    return dict.Items();

In summary, it doesn’t seem possible to set DataArray2D from JScript.

Setting the DataArray2D attribute in scripting

Last time I tried this, I gave up on JScript (it seemed impossible) and got something to work in Python.

In JScript, I kept getting errors like “# WARNING : 3392 – Invalid offset specified while extracting data from this attributeÈ.

si = Application
from win32com.client import constants as C            # win32com.client.constants

oObj = si.Selection(0)
oICEAttrMats = oObj.ActivePrimitive.AddICEAttribute("MyString", C.siICENodeDataString, C.siICENodeStructureArray, C.siICENodeContextSingleton)
oICEAttrMats.DataArray2D = [["a", "b", "c", "d"]]

x = oICEAttrMats.DataArray2D
print x
print len(x)
print len(x[0])
print len(x[0][0])

for d in x[0][0]:
    print d

# (((u'a', u'b', u'c', u'd'),),)
# 1
# 1
# 4
# a
# b
# c
# d

See also this Getting DataArray2D attribute values post.

The default project

The default project is the active project at startup (the project whose name appears in the Softimage title bar).

19-03-2013 4-45-51 PM

When you first install Softimage, the default project is XSI_SAMPLES.

After that, as you open scenes and exit and restart Softimage, the default project becomes the project that contained the scene you last opened. This is saved in your Default.xsipref file like this:

data_management.last_sequence_dir	= C:\Users\SOLIDANGLE\Projects\My Project\Scenes

But you can explicitly set a default project with the Project Manager, then that is saved in your Default.xsipref like this:

xsiprivate_unclassified.DS_SZ_LOAD_DEFAULT_PROJECT	= #STRI#C:\Users\SOLIDANGLE\Projects\Support

ICE: Storing vectors in a color at vertices property

The ICE trees for something suggested by Pooby in this Storing initial values thread on si-community. In this example, I’m trying to store per-point data into a per-sample attribute, so I have do a little extra work. I’m actually storing the point position multiple times for each vertex (one vertex had N samples), but I don’t know if it’s worth the effort to try and avoid that.

Getting the stored vectors back out:

Objects not saved normally?

So I saved my little trivial scene yesterday and I got this:

' WARNING : 3000 - Save: [1] objects were not saved normally
' WARNING : 3000 - -- [Scene_Root.Camera] was saved, but is disconnected from the scene. (Floating object)

Normally I ignore these warnings, but I didn’t like the idea of saving a scene with a disconnected camera. I remember when you were able to save scenes without a camera; you just couldn’t open them again.

My camera view was still working, so I checked it, and I had an extra camera (that I didn’t create).
Long story short, I saved the scene and it seemed ok after. The extra camera disappeared.

See also this post about WARNING 3000 Objects were not saved normally.

Finding degenerate polygons by area

Degenerate polygons are usually zero-area polygons.

Here’s a script that uses the ICE attribute PolygonArea to find polygons with area less than a specified epsilon:

si = Application
epsilon = 0.00001

# Get PolygonArea DataArray (which is a tuple)
attr = si.Selection(0).ActivePrimitive.GetICEAttributeFromName( "PolygonArea" )
areaData = attr.DataArray

# Find the indices of the bad polys
bad = [ x for x,y in enumerate( areaData ) if y < epsilon]

# Select the degenerates with a string like 'cube.poly[112,114,155]'
si.SelectGeometryComponents( 'cube.poly[%s]' % ','.join(str(i) for i in bad) )

### OR ###

# Get the actual Polygon objects
polys = si.Selection(0).ActivePrimitive.Geometry.Polygons
bad = []
for i in range( len(areaData) ):
	if areaData[i] < epsilon:
		bad.append( polys(i) )

si.SelectObj( polys )

Getting the DataArray2D for the Materials ICE attribute

Here’s the Python way:

Application.SelectObj("Pedestrian_Mesh.Actor_Copies", None, None);
o = Application.Selection(0)

a = o.ActivePrimitive.Geometry.GetICEAttributeFromName("Materials")
print len(a.DataArray2D)
print len(a.DataArray2D[0] )
print a.DataArray2D[0][0]
for s in a.DataArray2D[0][0]:
    print s

# 1
# 1
# (u'', u'Sources.Materials.PedestrianLib.Shoes', u'Sources.Materials.PedestrianLib.Hair', u'Sources.Materials.PedestrianLib.Legs', u'Sources.Materials.PedestrianLib.Skin', u'Sources.Materials.PedestrianLib.Shirt')
# Sources.Materials.PedestrianLib.Shoes
# Sources.Materials.PedestrianLib.Hair
# Sources.Materials.PedestrianLib.Legs
# Sources.Materials.PedestrianLib.Skin
# Sources.Materials.PedestrianLib.Shirt

And here’s how to do it in JScript:

o = Selection(0);

a = o.ActivePrimitive.Geometry.GetICEAttributeFromName("Materials");

x = new VBArray( a.DataArray2D ).toArray();
y = new VBArray( x[0] ).toArray();
for ( var i = 0; i < y.length; i++ )
    LogMessage( y[i] )