SUAttributeDictionarySetValue sets only key,


#1

Hello everyone!

I try to set dynamic_attributes dictionary value by using following code:

SUResult result = SU_ERROR_NONE;
SUEntityRef component1InstanceEntityRef = SUComponentInstanceToEntity(component1);
SUEntityGetAttributeDictionary(component1InstanceEntityRef, "dynamic_attributes", &component1DynamicAttributesDictionaryRef); 
SUTypedValueRef component1AttributeValue = SU_INVALID;
result = SUTypedValueCreate(&component1AttributeValue);
result = SUTypedValueSetString(component1AttributeValue, "Level1");
result = SUAttributeDictionarySetValue(component1DynamicAttributesDictionaryRef, "Position", component1AttributeValue);
result = SUTypedValueRelease(&component1AttributeValue);

After getting the value back using:

result = SUTypedValueCreate(&component1AttributeValue);
result = SUAttributeDictionaryGetValue(component1DynamicAttributesDictionaryRef, "Position", &component1AttributeValue);
SUTypedValueType type = SUTypedValueType_Empty;
SUTypedValueGetType(component1AttributeValue, &type);
SUStringRef stringValue = SU_INVALID;
result = SUStringCreate(&stringValue);
result = SUTypedValueGetString(component1AttributeValue, &stringValue);
size_t strLen = 0;
size_t copied = 0;
result = SUStringGetUTF8Length(stringValue, &strLen);
char * out = (char*)malloc(strLen + 1);
SUStringGetUTF8(stringValue, strLen, out, &copied);
out[strLen] = '\0';
fprintf(stdout, "%s\n", out);
result = SUTypedValueRelease(&component1AttributeValue);

get proper value written to stdout. But when I open my model in
SketchUp dynamic_atrributes dictionary of my component has only
"Position" key inserted with empty value. Does anyone know what could be
the reason of such behaviour ? What do I do wrong ?

Many thanks,
Paweł


#2

Do you perhaps have a complete example we can run and test? I cannot replicate what you describe.

Here is a quick test I did with our WritingToAskpFile example - modified:

#include <slapi/slapi.h>
#include <slapi/geometry.h>
#include <slapi/initialize.h>
#include <slapi/model/model.h>
#include <slapi/model/attribute_dictionary.h>
#include <slapi/model/entity.h>
#include <slapi/model/entities.h>
#include <slapi/model/face.h>
#include <slapi/model/edge.h>
#include <slapi/model/vertex.h>

int main() {
  // Always initialize the API before using it
  SUInitialize();
  // Create an empty model
  SUModelRef model = SU_INVALID;
  SUResult res = SUModelCreate(&model);
  // It's best to always check the return code from each SU function call.
  // Only showing this check once to keep this example short.
  if (res != SU_ERROR_NONE)
    return 1;
  // Get the entity container of the model
  SUEntitiesRef entities = SU_INVALID;
  SUModelGetEntities(model, &entities);
  // Create a loop input describing the vertex ordering for a face's outer loop
  SULoopInputRef outer_loop = SU_INVALID;
  SULoopInputCreate(&outer_loop);
  for (size_t i = 0; i < 4; ++i) {
    SULoopInputAddVertexIndex(outer_loop, i);
  }
  // Create the face
  SUFaceRef face = SU_INVALID;
  SUPoint3D vertices[4] = { { 0,   0,   0 },
                            { 100, 100, 0 },
                            { 100, 100, 100 },
                            { 0,   0,   100 } };
  SUFaceCreate(&face, vertices, &outer_loop);
  // Add the face to the entities
  SUEntitiesAddFaces(entities, 1, &face);

  // <attribute>
  SUResult result = SU_ERROR_NONE;
  SUAttributeDictionaryRef dictionary = SU_INVALID;
  SUEntityRef entity = SUFaceToEntity(face);
  SUEntityGetAttributeDictionary(entity, "api_test", &dictionary);
  SUTypedValueRef value = SU_INVALID;
  result = SUTypedValueCreate(&value);
  result = SUTypedValueSetString(value, "Hello World");
  result = SUAttributeDictionarySetValue(dictionary, "FooBar", value);
  result = SUTypedValueRelease(&value);
  // </attribute>

  // Save the in-memory model to a file
  SUModelSaveToFile(model, "new_model.skp");
  // Must release the model or there will be memory leaks
  SUModelRelease(&model);
  // Always terminate the API when done using it
  SUTerminate();
  return 0;
}

When I open the file I see the expected dictionary with key and value:


#3

Have you checked the results of each of your calls?


#4

Hello !

What I try to achievie is having dynamic components instances atrributes values to be set via API - I have a template file which contains all the dynamic components definitions I need, and use it as a basis of new .skp file. When creating file i put component instances in places and try to set their dynamic_attributes values using know keys like ‘Position’. But what happens afrer executing my code is new ‘Position’ key is created in dynamic_attributes dict, but it has empty value.

By dynamic_attributes dictionary i understand one shown in dialog box ( googled image ):

[Dialog Box][1]

I will post full code on monday, i don’t have acces to it today.

SUResult OpenTemplateFile(const char * filePath, SUModelRef * modelRef, SUEntitiesRef * entities)
{
    SUResult res = SUModelCreateFromFile(modelRef, filePath);
    if (res == SU_ERROR_NONE)
    {
        res = SUModelGetEntities(*modelRef, entities);
        size_t r = 0;
        SUModelGetNumComponentDefinitions(*modelRef, &r);
        fprintf(stdout, "Number of component definitions: %d\n", r);
    }
    return res;
}

SUTransformation GetTranslation(double tx, double ty, double tz)
{

    SUTransformation transformation;

    transformation.values[0] = 1.0;
    transformation.values[1] = 0.0;
    transformation.values[2] = 0.0;
    transformation.values[3] = 0.0;

    transformation.values[4] = 0.0;
    transformation.values[5] = 1.0;
    transformation.values[6] = 0.0;
    transformation.values[7] = 0.0;

    transformation.values[8] = 0.0;
    transformation.values[9] = 0.0;
    transformation.values[10] = 1.0;
    transformation.values[11] = 0.0;

    transformation.values[12] = tx;
    transformation.values[13] = ty;
    transformation.values[14] = tz;
    transformation.values[15] = 1.0;

    return transformation;
}

SUResult CreateComponentInstances(SUModelRef model, SUEntitiesRef entities, SULayerRef layerRef)
{
    SUComponentDefinitionRef  componentDefinitions[4] = { SUComponentDefinitionRef(), SUComponentDefinitionRef(), SUComponentDefinitionRef(), SUComponentDefinitionRef() };
    SUResult result = SU_ERROR_NONE;
    size_t retrieved = 0;
    size_t len = 4;

    result = SUModelGetComponentDefinitions(model, len, componentDefinitions, &retrieved);
    SUComponentInstanceRef component1;
    SUComponentInstanceRef component2;
    SUComponentInstanceRef component3;
    SUComponentInstanceRef component4;

    result = SUComponentDefinitionCreateInstance(*componentDefinitions, &component1);
    result = SUComponentDefinitionCreateInstance(*(componentDefinitions + 1), &component2);
    result = SUComponentDefinitionCreateInstance(*(componentDefinitions + 2), &component3);
    result = SUComponentDefinitionCreateInstance(*(componentDefinitions + 3), &component4);

    result = SUEntitiesAddInstance(entities, component1, NULL);
    result = SUEntitiesAddInstance(entities, component2, NULL);
    result = SUEntitiesAddInstance(entities, component3, NULL);
    result = SUEntitiesAddInstance(entities, component4, NULL);

    SUStringRef name = SU_INVALID;
    SUStringCreate(&name);
    size_t arrayLength = 20;
    unichar charArray[20];
    size_t numberOfCharsCopied;

    result = SUComponentDefinitionGetName(*componentDefinitions, &name);
    SUStringGetUTF16(name, arrayLength, charArray, &numberOfCharsCopied);

    result = SUComponentDefinitionGetName(*(componentDefinitions + 1), &name);
    SUStringGetUTF16(name, arrayLength, charArray, &numberOfCharsCopied);

    result = SUComponentDefinitionGetName(*(componentDefinitions + 2), &name);
    SUStringGetUTF16(name, arrayLength, charArray, &numberOfCharsCopied);

    result = SUComponentDefinitionGetName(*(componentDefinitions + 3), &name);
    SUStringGetUTF16(name, arrayLength, charArray, &numberOfCharsCopied);

    SUDrawingElementRef component1DE = SUComponentInstanceToDrawingElement(component1);
    SUDrawingElementRef component2DE = SUComponentInstanceToDrawingElement(component2);
    SUDrawingElementRef component3DE = SUComponentInstanceToDrawingElement(component3);
    SUDrawingElementRef component4DE = SUComponentInstanceToDrawingElement(component4);

    result = SUDrawingElementSetLayer(component1DE, layerRef);
    result = SUDrawingElementSetLayer(component2DE, layerRef);
    result = SUDrawingElementSetLayer(component3DE, layerRef);
    result = SUDrawingElementSetLayer(component4DE, layerRef);


    SUTransformation component1Transform = GetTranslation(10.0, 10.0, 0.0);
    SUTransformation component2Transform = GetTranslation(0.0, 10.0, 0.0);
    SUTransformation component3Transform = GetTranslation(10.0, 0.0, 0.0);
    SUTransformation component4Transform = GetTranslation(20.0, 20.0, 0.0);

    result = SUComponentInstanceSetTransform(component1, &component1Transform);
    result = SUComponentInstanceSetTransform(component2, &component2Transform);
    result = SUComponentInstanceSetTransform(component3, &component3Transform);
    result = SUComponentInstanceSetTransform(component4, &component4Transform);


    SUEntityRef component1InstanceEntityRef = SUComponentInstanceToEntity(component1);
    SUAttributeDictionaryRef component1DynamicAttributesDictionaryRef = SU_INVALID;
    SUEntityGetAttributeDictionary(component1InstanceEntityRef, "dynamic_attributes", &component1DynamicAttributesDictionaryRef); 
    SUTypedValueRef component1AttributeValue = SU_INVALID;
    result = SUTypedValueCreate(&component1AttributeValue);
    result = SUTypedValueSetInt32(component1AttributeValue, 24);
    result = SUAttributeDictionarySetValue(component1DynamicAttributesDictionaryRef, "Position", component1AttributeValue);
    result = SUTypedValueRelease(&component1AttributeValue);

    result = SUTypedValueCreate(&component1AttributeValue);
    const char v[] = { 'F', 'U', 'L', 'L', '\0' };
    result = SUTypedValueSetString(component1AttributeValue, v);
    result = SUAttributeDictionarySetValue(component1DynamicAttributesDictionaryRef, "FullName", component1AttributeValue);
    result = SUTypedValueRelease(&component1AttributeValue);

    result = SUTypedValueCreate(&component1AttributeValue);
    result = SUAttributeDictionaryGetValue(component1DynamicAttributesDictionaryRef, "FullName", &component1AttributeValue);
    SUTypedValueType type = SUTypedValueType_Empty;
    SUTypedValueGetType(component1AttributeValue, &type);
    SUStringRef stringValue = SU_INVALID;
    result = SUStringCreate(&stringValue);
    result = SUTypedValueGetString(component1AttributeValue, &stringValue);
    size_t strLen = 0;
    size_t copied = 0;
    result = SUStringGetUTF8Length(stringValue, &strLen);
    char * out = (char*)malloc(strLen + 1);
    SUStringGetUTF8(stringValue, strLen, out, &copied);
    out[strLen] = '\0';
    fprintf(stdout, "%s\n", out);
    result = SUTypedValueRelease(&component1AttributeValue);

    size_t numKeys = 0;
    size_t keysRetrieved = 0;
    result = SUAttributeDictionaryGetNumKeys(component1DynamicAttributesDictionaryRef, &numKeys);
    //SUStringRef * keys = (SUStringRef*)malloc(numKeys * sizeof(SUStringRef));
    std::vector<SUStringRef> keys(numKeys);
    for (int i = 0; i < numKeys; i++)
    {
        SUStringCreate(&keys[i]);
    }
    result = SUAttributeDictionaryGetKeys(component1DynamicAttributesDictionaryRef, numKeys, &keys[0], &keysRetrieved);

    for (int i = 0; i < numKeys; i++)
    {
        size_t strLen = 0;
        size_t copied = 0;
        result = SUStringGetUTF8Length(keys[i], &strLen);
        char * out = (char*)malloc(strLen +1);
        out[strLen] = '\0';
        SUStringGetUTF8(keys[i], strLen, out, &copied);

        fprintf(stdout, "%s\n", out);
    }

    return result;
}


int main()
{
    SUInitialize();

    SUModelRef modelRef = SU_INVALID;
    SUEntitiesRef entitiesRef = SU_INVALID;
     
    const char * fileName = "C:\\1.skp";

    SUResult result = OpenTemplateFile(fileName, &modelRef, &entitiesRef);

    SULayerRef layerA = SULayerRef();
    SULayerRef layerB = SULayerRef();
    SULayerRef layerC = SULayerRef();

    result = SULayerCreate(&layerA);
    result = SULayerCreate(&layerB);
    result = SULayerCreate(&layerC);

    SUModelAddLayers(modelRef, 1, &layerA);
    SUModelAddLayers(modelRef, 1, &layerB);
    SUModelAddLayers(modelRef, 1, &layerC);

    result = SULayerSetName(layerA, "layerA");
    result = SULayerSetName(layerB, "layerB");
    result = SULayerSetName(layerC, "layerC");

    result = SULayerSetVisibility(layerA, true);
    result = SULayerSetVisibility(layerB, true);
    result = SULayerSetVisibility(layerC, true);

    result = CreateComponentInstances(modelRef, entitiesRef, layerA);

    SUResult saveResult = SUModelSaveToFile(modelRef, "C:\\newModel.skp");
    SUModelRelease(&modelRef);

    SUTerminate();

    return 0;
}

#5

Yes, all the results were ‘NO_ERROR’


#6

Are you using an extension “Attribute Visualizer” or does that come with Sketchup Pro?


#7

I wrote a small tool to inspect attributes:
http://extensions.sketchup.com/en/content/attribute-helper

@eneroth3 also got a good extension if you also need to edit the attributes:
http://extensions.sketchup.com/en/content/eneroth-attribute-editor
It even let you inspect attributes of vertices if you need to - which are otherwise not selectable in SketchUp and harder to inspect.