Isotropix Forums

Exporting property values as strings of different lengths

Clarisse Scripting related topics

Exporting property values as strings of different lengths

Unread postby jboissinot » Wed Feb 13, 2019 1:54 am

Hi,

Unlike other property types that we can define with a constant size, we were wondering if it's possible to set the values in a char type property with strings of different lengths?

In fact, we noticed that the string values were not properly set while trying to store them with an object scene path or asset name for instance, which can have different lengths.
To fix this, we ended up filling the strings with spaces so that they fit in the char property size as a workaround but it's not the best.

The way the set_string() is built - from what I could read in the documentation - is that it stores every char of a string but doesn't work if the string length doesn't match the char property size.

Thanks,
Jeremy
jboissinot
 
Posts: 4
Joined: Tue Jan 29, 2019 10:36 pm

Re: Exporting property values as strings of different length

Unread postby anemoff » Thu Feb 14, 2019 5:57 pm

Hi Jeremy,

jboissinot wrote:Unlike other property types that we can define with a constant size, we were wondering if it's possible to set the values in a char type property with strings of different lengths?

Yes, you can write multiple values in a single string property. But you will need to separate them with a character separator (space or ';' for example) to be able to split them back when reading them in the other application.
For example: "0.1234 1.23 0.000000003 5.45143 ..."
If you have lots of points and lots of values per point it will result in a huge string. If so, I would recommend converting the string to binary form (hexadecimal) when writing it, to save some memory.
And, there's also the problem that float or double values might be truncated when converted to string, losing precision.

jboissinot wrote:In fact, we noticed that the string values were not properly set while trying to store them with an object scene path or asset name for instance, which can have different lengths.
To fix this, we ended up filling the strings with spaces so that they fit in the char property size as a workaround but it's not the best.

The way the set_string() is built - from what I could read in the documentation - is that it stores every char of a string but doesn't work if the string length doesn't match the char property size.

- Are you creating the string property by script or using the Property Editor?
- What size are you giving to your string property when initializing it?
- ResourceProperty.set_string will truncate the given string to the size (item value count, aka dimension or extent) that was initially given when the property was created with "init". Resizing a value afterward through the ResourceProperty API is not straightforward.
- If possible I suggest using the API in IOHelpers.edit_particles_property, to set/edit values as I dit in my example. It will automatically resize each value to the size of the new value size, otherwise it's pretty heavy to do by yourself, especially by script.
Anthony Nemoff
Isotropix
R&D Engineer
User avatar
anemoff
 
Posts: 87
Joined: Wed Jan 13, 2016 10:10 am

Re: Exporting property values as strings of different length

Unread postby jboissinot » Tue Feb 19, 2019 12:56 am

Hi Anthony,

I'm creating the string property by script and set a size of 100 - but could be shorter, maybe 40 or 50 would be long enough - when initializing it as you can see in the following code snippet as an example:

Code: Select all
prop = createProperty('name')
prop.init(ix.api.ResourceProperty.TYPE_CHAR, 100, nbPoints)


Then, I simply set the property name value while parsing the points with the set_string() - with the name variable having a different length for each point for instance:

Code: Select all
prop.set_string(index, name)


But, I'm getting the following error when exporting the Alembic file:

Code: Select all
Alembic export: an error occured during the export process: OArrayProperty::set()
ERROR: EXCEPTION:
Illegal NULL character found in string data


I ended up filling the name with empty spaces to fix the issue for the moment with something like this:

Code: Select all
prop.set_string(index, '{:100}'.format(name))


So, if I understand correctly, you'd recommend setting all the string values at once as one single string and split with a character separator?
jboissinot
 
Posts: 4
Joined: Tue Jan 29, 2019 10:36 pm

Re: Exporting property values as strings of different length

Unread postby anemoff » Tue Feb 19, 2019 5:52 pm

Hi,

thanks for the details.

Actually, I misunderstood your question on your first post. So you can forget my previous answer. Sorry about that! :?
I thought you wanted to store multiple values in a single string property value.

About your original question, yes, that's that possible using IOHelpers.
Check the example in my other post, the one at the end where I create a string property.

python code

# create the string values for each point
string_values= []
for i in range(point_count):
# each string has an increasing size
string_values.append('text_%s' % str(i).zfill(i + 1))

# this method assumes the property already exists
set_point_property_values(particle_container, 'my_string_prop', string_values)

Let me know if you need more help with this.

In fact, the ResourceProperty C++ API has different "init" method that takes an array of sizes along with an array of values, so that you can specify the size of each value instead of having to set the same size for all of them.

cpp code

//! \brief Init the items of the property with different numbers of values
//! \param[in] type the type of values stored in each item
//! \param[in] item_value_count array containing the number of values for each item
//! \param[in] item_count the number of items
void init(const Type& type, const unsigned int *item_value_count, const unsigned int& item_count);


But sadly, this method isn't available in the Clarisse Python API because SWIG (the tool that creates the Python bindings) doesn't support C++ method overloads (SWIG: Ambiguity in Overloading). The problem is that both methods have the same name but different parameter types, and only the 1st one becomes available in Python because of SWIG's limitation.

I really recommend you to use the IOHelpers API, which does a lot of stuff under the hood that isn't always possible to do in Python (like resizing or replacing existing property values).
Let us know if you chose to do so and if you need help rewriting some of your scripts with IOHelpers.

-----

About the Alembic error:

jboissinot wrote:But, I'm getting the following error when exporting the Alembic file:

Code: Select all
Alembic export: an error occured during the export process: OArrayProperty::set()
ERROR: EXCEPTION:
Illegal NULL character found in string data


This is an error in the Alembic library caused by the Clarise string property which is partially uninitialized when you don't fill the extra space.
I haven't managed to reproduce the same error, but I'm pretty sure the reason is that when you declare a ResourceProperty of type TYPE_CHAR, where each item has a size of N, if you don't fill all the N characters, then the remaining characters will contain random uninitialized values among which, maybe, the null character '0' which indicates the end of the string.

For example, if you set "hello" in a string of capacity 100, and don't fill the remaining characters, it could look like this in memory:
Code: Select all
[ h , e, l, l, o, 3, z, g, T, 0, ... ]

Clarisse doesn't know the string actually ends after "hello", it knows it has 100 characters so it will export all of them.
Then Alembic expects a string of exactly 100 characters but finds an unexpected null character before the end, and throws an error.
That's why filling the values with spaces fixes the error.

-----

Cheers,
Anthony Nemoff
Isotropix
R&D Engineer
User avatar
anemoff
 
Posts: 87
Joined: Wed Jan 13, 2016 10:10 am


Return to Scripting