UserDataMap

Object Hierarchy | Related C++ Class: UserDataMap | Supported Parameter List: UserDataMap

Inheritance

SIObject
   ProjectItem
       Property
          UserDataMap

Introduced

3.0

Description

The UserDataMap is a Property that can be attached to any cluster. It permits the storage of variable length binary user data on the individual components of a geometry. The data is stored as part of the scene file and can be accessed via plug-ins using the Object Model.

Softimage plug-ins (both persistent and immediate effects) can use this property to save and retrieve data that is associated with individual vertices, polygons, edges, or other components of an object. Example data possibilities include custom game structures, raw simulation data, matrices, comments and images.

There are two ways that a UserDataMap can be used - for binary data or for templated data. With a Binary UserDataMap, the structure of the user data is left completely up to the plug-in. This is well suited to C++ plug-ins. However, as the examples below demonstrate, it is possible to access this data through scripting by using strings. The second type of UserDataMap uses a CustomProperty to strictly define the structure of the user data (see UserDataMap.Template). Templated user data can be inspected in the UI (see InspectUserData) in addition to scripting and C++ access.

UserDataMaps are created with CreateUserDataMap or SceneItem.AddProperty.

UserDataMap differs from the CustomProperty and UserDataBlob objects in that it stores separate data for each individual component of a cluster. For example a cluster with ten polygons will have ten different UserDataItem objects. It is possible to enumerate the UserDataItem objects in a UserDataMap using UserDataMap.Item, or the VBScript "for each" loop construct, or the JScript Enumerator object. It is also possible to access the contents of a UserDataMap directly with UserDataMap.ItemValue.

The UserDataMap is similar to a ClusterProperty, which also stores per-component data, but the UserDataMap allows variable length data, whereas the ClusterProperty objects always store a fixed number of Doubles at each component.

The User Data Map provides similar functionality to that available from the SAAPHIRE SAA_subelement* UserData functions. For example, the Name of the property corresponds to the Tag argument to functions like SAA_subelementSetUserData.

It is possible to save a preset of a user data map and to reapply the user data on a different object. However, for the best results, the number of components in both clusters should be the same.

Methods

AddCustomOp

AddScriptedOp

AddScriptedOpFromFile

AnimatedParameters2

BelongsTo

Clear

ClearItem

EvaluateAt

GetICEAttributeFromName

GetItem2

GetItemSize2

GetItemValue2

IsA

IsAnimated2

IsClassOf

IsEqualTo

IsKindOf

IsLocked

IsSelected

LockOwners

SetAsSelected

SetCapabilityFlag

SetLock

TaggedParameters

UnSetLock

 

 

 

Properties

Application

Branch

BranchFlag

Capabilities

Categories

Count

Families

FullName

Help

ICEAttributes

IsEmpty

Item

ItemSize

ItemValue

LittleEndian

LockLevel

LockMasters

LockType

Model

Name

NestedObjects

ObjectID

Origin

OriginPath

Owners

Parameters

Parent

Parent3DObject

PPGLayout

Selected

Singleton

Template

Type

 

 

 

Examples

1. VBScript Example

'example giving an overview of accessing per-component
'user data on a cluster

dim oObj, oCluster, oUDProp, i, oUserDataAtIndex2

set oObj = CreatePrim( "Sphere", "MeshSurface" )
SetValue oObj & ".polymsh.geom.subdivu", 1
SetValue oObj & ".polymsh.geom.subdivv", 1

'Create a cluster covering all edges on the geometry
set oCluster = oObj.ActivePrimitive.Geometry.AddCluster( siEdgeCluster,"UserDataCls" )
   set oUDProp = oCluster.AddProperty( "UserDataMap",,"UserDataExample" )
   
'UserDataMap
logmessage oUDProp.Type

'Assign user data to a particular index
oUDProp.ItemValue(2) = "Some String Data"

'Another way to do the same thing is to use a UserDataItem object
oUDProp.Item(3).Value = "String data for index 3"

'Erase the data we just placed at 3
oUDProp.ClearItem(3)

'Now look at all the user data in the property looking for non-empty content
for i = 0 to oUDProp.Count
   if ( not oUDProp.IsEmpty(i) ) then
       logmessage "Found data with size " & oUDProp.ItemSize(i) & " at cluster index " & i
   end if
next 


'Output of this script is:
'INFO : "UserDataMap"
'INFO : "Found data with size 32 at cluster index 2"

2. JScript Example

//example giving an overview of accessing per-component
//user data on a cluster

var oObj = CreatePrim( "Sphere", "MeshSurface" ) ;

SetValue( oObj + ".polymsh.geom.subdivu", 1 ) ;
SetValue( oObj + ".polymsh.geom.subdivv", 1 ) ;

//Create a cluster covering all edges on the geometry
var oCluster = oObj.ActivePrimitive.Geometry.AddCluster( siEdgeCluster, "UserDataCls" ) ;
var oUDProp = oCluster.AddProperty( "UserDataMap",false,"UserDataExample" ) ;

//UserDataMap
logmessage( oUDProp.Type ) ;

//Assign user data to a particular index
oUDProp.ItemValue(2) = "Some String Data"

//Or we can use a UserDataItem object as another way to set data
oUDProp.Item(3).Value = "String data for index 3"

//Erase the data we just placed at 3
oUDProp.ClearItem(3)

//Now look at all the user data in the property looking for non-empty content
for( var i = 0 ; i < oUDProp.Count ; i++ )
{
   if ( !oUDProp.IsEmpty(i) )
   {
       logmessage( "Found data with size " + oUDProp.ItemSize(i) + " at cluster index " +  i ) ;
   }
}
//Output of this script is:
//INFO : "UserDataMap"
//INFO : "Found data with size 32 at cluster index 2"

3. PerlScript Example

#example giving an overview of accessing per-component
#user data on a cluster

$oObj = $Application->CreatePrim( "Sphere", "MeshSurface" ) ;

$Application->SetValue( $oObj->{Name} . ".polymsh.geom.subdivu", 1 ) ;
$Application->SetValue( $oObj->{Name} . ".polymsh.geom.subdivv", 1 ) ;


$oCluster = $oObj->{ActivePrimitive}->{Geometry}->AddCluster( "edge", "UserDataCls" ) ;
$oUDProp = $oCluster->AddProperty( "UserDataMap",0,"UserDataExample" ) ;

#UserDataMap
$Application->Logmessage( $oUDProp->{Type} ) ;

#Assign user data to a particular index
$oUDProp->SetProperty( 'ItemValue', 2, "Some String Data" );

#Or we can use a UserDataItem object as another way to set data
$oUDProp->Item(3)->{Value} = "String data for index 3" ;

#Erase the data we just placed at 3
$oUDProp->ClearItem(3) ;

#Now look at all the user data in the property looking for non-empty content

my $i = 0 ;

while ( $i < $oUDProp->{Count} ) {
   if ( !$oUDProp->IsEmpty($i) ) {
       $Application->Logmessage( "Found data with size " . 
                              $oUDProp->ItemSize($i) . 
                              " at cluster index " . $i ) ;
   }

   $i += 1 ;
}

#Output of this script is:
#INFO : "UserDataMap"
#INFO : "Found data with size 32 at cluster index 2"

4. VBScript Example

'example demonstrating the how to display the entire contents
'of a binary user data map in the command history window.
'(For an example showing how to show the contents of a templated user data map
'see the Info OM Netview page that is part of XSI Local\Tools)

dim oObj, oCluster, oUDProp, i

'First set up a little demo scenario
set oObj = CreatePrim( "Arc", "NurbsCurve" )
set oCluster = oObj.ActivePrimitive.Geometry.AddCluster( siVertexCluster,"PntCluster",Array(1,4,7,10,13,16) )
   set oUDProp = oCluster.AddProperty( "UserDataMap",,"UserDataExample" )
   
'Fill in the user data with the string version of the index
for i = 0 to oUDProp.Count - 1
   oUDProp.Item( i ).Value = CStr( i )
next

SelectObj oUDProp

'Then dump out all the content that was added
TraceSelectedUserDataMap

'Output of this script will look approximately like this:
'INFO : "User Data Map: arc.crvlist.cls.PntCluster.UserDataExample"
'INFO : "Size of User Data Map 6- Size of Cluster 6"
'INFO : "Property was created on little-endian computer"
'INFO : "Contents:"
'INFO : "Item 0 pnt(1): 0 "
'INFO : "Item 1 pnt(4): 1 "
'INFO : "Item 2 pnt(7): 2 "
'INFO : "Item 3 pnt(10): 3 "
'INFO : "Item 4 pnt(13): 4 "
'INFO : "Item 5 pnt(16): 5 "

'The number of components with user data could get huge so this constant 
'constrains the size of the output to reasonable proportions
const g_MapItemsDisplay = 256
const g_ShowEmptyItems = false



sub TraceSelectedUserDataMap
   'This example could easily to enhanced to loop through multiple selections
   'but for the sake of simplicity it only looks at the first item

   if ( selection.Count > 0 ) then
       if ( typename( selection( 0 ) ) = "UserDataMap" ) then
          TraceUserDataMap( selection( 0 ) )
       else
          logmessage "Please select a user data map and try again"
       end if
   else
       logmessage "Please select a user data map and try again"
   end if
end sub

sub TraceUserDataMap( in_oUDM )
   dim i, oItem, cntCluster, byteString, j, str, val

   cntCluster = in_oUDM.Parent.Elements.Count

   Logmessage "User Data Map: " & in_oUDM.FullName
   Logmessage "Size of User Data Map " & in_oUDM.Count & "- Size of Cluster " & cntCluster
   Logmessage "Contents:"

   dim oCluster, oClusterElementsCollection, aElements
   set oCluster = in_oUDM.Parent      
   set oClusterElementsCollection = oCluster.Elements
   aElements = oClusterElementsCollection.Array  

   dim iElementInCluster, strItemDesc

   dim cntItems
   cntItems = in_oUDM.Count

   dim cntDisplayedItems
   cntDisplayedItems = 0

   for i = 0 to ( cntItems - 1)

       if ( i < cntCluster ) then
          iElementInCluster = aElements(i)  
          strItemDesc = "Item " & i & " " & oCluster.type & "(" & iElementInCluster & "): "
       else
          strItemDesc = "Item " & i & " " & oCluster.type & "(INVALID INDEX): "
       end if

       set oItem = in_oUDM.Item( i )

       if ( not oItem.IsEmpty ) then

          'We convert the contents into a byte by byte description
          'because we don't know if this is a safe to display unicode string

          strItemDesc = strItemDesc & GetUserDataContentsString( oItem )

          logmessage strItemDesc

          cntDisplayedItems = cntDisplayedItems + 1

          if ( cntDisplayedItems = g_MapItemsDisplay ) then
              exit for
          end if

       elseif ( g_ShowEmptyItems ) then
          logmessage strItemDesc & " is empty"
       end if
              
   next
end sub

'Produces a string representation of the user data
function GetUserDataContentsString( in_UserDataItem )

   dim strValue
   strValue = in_UserDataItem.Value

   dim j


   'Also attempt to produce a string representation

   dim strAsString
   for j = 1 to Len( strValue )
       val = Asc( Mid( strValue, j, 1 ) )

       'We only accept the basic ascii values - other content is
       'not necessary safe to print.  For supporting non-English 
       'characters, line breaks and tabs this logic would need 
       'to be more sophisticated

       if (( val < 127 ) AND ( val > 31 )) then
          strAsString = strAsString & Chr( val )
       else
          'we assume that there is binary content
          strAsString = strAsString & "."
       end if
   next 

   GetUserDataContentsString = strAsString
end function

5. VBScript Example

'example of how to access a templated UserDataMap from from scripting.

'In this example we create user data for an imaginary game on the vertices of 
'a sphere.
'
'The user data template is designed to match an associated structure in the game engine,
'and consists of 5 parameters ("ImagePath", "AttachmentPoint", "FixedPoint", "ZetaFactor",
'and "Friction")
'
'This example creates the object and sets some example values on a few points.  (A user could also
'add and edit these values from the user interface using the InspectUserData command)
'
'When you run this example this is the output in the log window:
'
'INFO : "User data on sphere.polymsh.cls.AllVertices.GameData"
'INFO : "pnt[12]:  ZetaFactor:0.2 Friction:64 AttachmentPoint Image: image12.tif"
'INFO : "pnt[31]:  ZetaFactor:0.9 Friction:12 AttachmentPoint FixedPoint Image: unknown"
'INFO : "pnt[44]:  ZetaFactor:0.5 Friction:28 FixedPoint Image: image1.jpg"

option explicit

const g_ClusterName = "AllVertices"
const g_UserDataMapName = "GameData"
const g_TemplateName = "VertexInfoTemplate"

newscene ,false

dim oSphere, oUserDataMap
set oSphere = ActiveSceneRoot.AddGeometry( "Sphere", "MeshSurface" )

'Create templated user data map - currently it is has no user data
set oUserDataMap = SetupObject( oSphere )

'Set these user data values on vertex 44
call AddUserData( oUserDataMap , 44, "image1.jpg", false, true, 0.5, 28 )

'Set different values on points 12
call AddUserData( oUserDataMap , 12, "background14.tif", true, false, 0.1, 39 )

'Change our minds about point 12
call AddUserData( oUserDataMap , 12, "image12.tif", true, false, 0.2, 64 )

call AddUserData( oUserDataMap , 31, "unknown", true, true, 0.9, 12 )

call LogUserData( oUserDataMap )

'On the given object create a UserDataMap for the game data
function SetupObject( in_oObj )
   dim oCluster, oPSet, oUserDataMap

   'Test if we have already setup this object
   on error resume next
   set oUserDataMap = in_oObj.ActivePrimitive.Geometry._
                        Clusters( g_ClusterName ).Properties( g_UserDataMapName )
   on error goto 0

   if typename( oUserDataMap ) = "UserDataMap" then
       'Our user data map already exists
       set SetupObject = oUserDataMap
       exit function
   end if 

   set oCluster = in_oObj.ActivePrimitive.Geometry.AddCluster( siVertexCluster, g_ClusterName ) 
   set oPSet = CreateTemplate( oCluster )
       
   set oUserDataMap = oCluster.AddProperty( "UserDataMap",,g_UserDataMapName )

   'Associate the template with our user data map
   set oUserDataMap.Template = oPSet

   'Return the newly created User Data Map
   set SetupObject = oUserDataMap
end function

'This function creates the template that defines the format of the data inside our UserDataMap
'The new template is returned.
'Note: this function does not associate the template with any user data map, or set any values on
'the user data map.
function CreateTemplate( in_oParentObject )

   dim oPSet
   set oPSet = in_oParentObject.AddProperty( "Custom_parameter_list",, g_TemplateName )

   oPSet.AddParameter "ImagePath", siString
   oPSet.AddParameter "AttachmentPoint", siBool, , , ,, , false
   oPSet.AddParameter "FixedPoint", siBool, , , ,, , false
   oPSet.AddParameter "ZetaFactor", siDouble, , , , , , 0.0, 0.0, 1.0
   oPSet.AddParameter "Friction", siUByte, , , , , , 64, 0, 128

   set CreateTemplate = oPSet
end function

'Given specific game parameter values, this routine will save those values
'on the specified vertex of the UserDataMap
sub AddUserData( in_oUDM, in_CompIndex, in_ImagePath, in_AttachPoint, in_FixedPoint, in_ZetaFactor, in_Friction )

   'Get access to the Template for this user data map
   dim oTemplate
   set oTemplate = in_oUDM.Template

   'Fill in the parameters on the template

   oTemplate.Parameters( "ImagePath" ).Value = in_ImagePath
   oTemplate.Parameters( "AttachmentPoint" ).Value = in_AttachPoint
   oTemplate.Parameters( "FixedPoint" ).Value = in_FixedPoint
   oTemplate.Parameters( "ZetaFactor" ).Value = in_ZetaFactor
   oTemplate.Parameters( "Friction" ).Value = in_Friction

   'Now that the parameters are specified we need to associated
   'these values with the specified vertex
   in_oUDM.ItemValue(in_CompIndex) = oTemplate.BinaryData
              
end sub

'This routine prints out the contents of our user data map
sub LogUserData( in_oUDM )
   dim oTemplate, i, strAttachPnt, strFixedPnt

   Logmessage "User data on " & in_oUDM

   set oTemplate = in_oUDM.Template

   for i = 0 to in_oUDM.count

       'We can only print out non-empty user data items
       if ( NOT in_oUDM.IsEmpty( i ) ) then

          'Take the values from the user data and put them in the template
          'so that we can read them
          oTemplate.BinaryData = in_oUDM.ItemValue( i )

          'Look at the boolean values to convert into readable strings
          if ( oTemplate.Parameters("AttachmentPoint").Value ) then
              strAttachPnt = "AttachmentPoint "
          else
              strAttachPnt = ""
          end if

          if ( oTemplate.Parameters("FixedPoint").Value ) then
              strFixedPnt = "FixedPoint "
          else
              strFixedPnt = ""
          end if
                 
          'Print a 1 line representation of all the values on this particular point
          logmessage "pnt[" & i & "]: " & _
                     " ZetaFactor:" & oTemplate.Parameters("ZetaFactor").Value & _
                     " Friction:" & oTemplate.Parameters("Friction").Value & _
                     " " & strAttachPnt & strFixedPnt & _
                      "Image: " & oTemplate.Parameters("ImagePath").Value 
                         
       end if
   next 
end sub

See Also

UserDataItem

UserDataBlob

CustomProperty

Cluster

ClusterProperty

 

 

 



Autodesk Softimage v7.5