Calling dynamic components redraw from C importer

Hi,
I’m trying to make an importer for SketchUp using the C API that will download some dynamic components from the 3D warehouse, places them in a file and changes some properties on these components. I have a couple of problems with these components:

  1. I cannot set some parameters from some components, while I can set them on others. I will provide more information below.
  2. I have to call Redraw from the Dynamic Components menu manually after importing a component, otherwise the visualization doesn’t update. I would like to be able to call this function from the C API, but I haven’t found a way thus far.

All help is greatly appreciated!

Extra information for problem 1:
I can set the height of the following component: https://3dwarehouse.sketchup.com/warehouse/v1.0/publiccontent/d68c504c-a4cc-4640-b5ea-5b3a6cff2a6e
But I cannot set the height for this component: https://3dwarehouse.sketchup.com/warehouse/v1.0/publiccontent/cff9cf2a-8a69-4bca-a9a5-157c69fc8f78
I’ve written the following code to set the height:
SetDoubleAttribute(entity, "dynamic_attributes", "lenz", 114.7244094f);

SetDoubleAttribute(SUEntityRef& entity, const char* dictionary, const char* key, double value)
{
	// Prepare value
	SUTypedValueRef typedValue;
    SUSetInvalid(typedValue);
    SUTypedValueCreate(&typedValue);
    SUTypedValueSetDouble(typedValue, value);
	
	// Set the value
	SUAttributeDictionaryRef dic;
    SUSetInvalid(dic);
    SUEntityGetAttributeDictionary(entity, dictionary, &dic);
    SUAttributeDictionarySetValue(dic, key, typedValue);
}

Does this importer run from within the SketchUp application process ?

I am guessing NO because the C API is not yet a “live” API that can modify the current model.

The answer weighs upon …

The DC code is implemented in Ruby, so can only run within the SketchUp application process.
But since Ruby is implemented in C, and has it’s own C API, then calls to Ruby object methods (ie, SketchUp’s Ruby API and model objects) can be called from C in several ways.

So, if the answer is yes, your importer is running within SketchUp, then you can call the DC code.
The simpliest is …

rb_eval_string("$dc_observers.get_latest_class.redraw_with_undo(dc_instance)")

… where dc_instance is a Ruby-side reference the the DC instance you wish to draw.

There are also other Ruby C API functions that can be used for more complicated Ruby calls from C.
The subject of Ruby C extensions is too involved for this discussion. See the example posted at GitHub …

The DCs are a bit weird. It really helps if you understand Ruby, and have experience crafting DCs manually in SketchUp.

You cannot set the standard DC attributes directly. So you’d need to create a custom attribute, let’s name it “height” and set it to 114.7244094.
Then set the “_lenz_formula” attribute to point at the “height” attribute.

That said, … the Dynamic Components extension is proprietary closed source and the interaction of the dynamic attributes and it’s code is quite complex. There is no actual public API nor documentation for developers. (Note the the C API only has informational getter functions that are DC specific.)

Any workarounds we post in the forums are really “hacks” and not guaranteed to work in future releases as the DC code could be changed at any time, without notice.

Regardless, your best advice for crafting dynamic components will come from the forum subcategory:

In that subcategory I’ve created a wikilist of DC Resources …

1 Like

Hi Dan,
Thank you for your fast and complete response!

The importer runs from within the SketchUp application, it is based on the xml_to_skp example in the SDK sample folder. I will try to call the DC code in order to redraw the dynamic component. I’ll also check if making a custom attribute will fix my issue, even though it might break in future releases.

Do you know if setting the dynamic attributes using the API will ever be possible in the future?

Oh whoopsie. That example should have been removed from the SDK at the last release.

The old C++ SDK has been removed as of version 2019.2 and the old “drop in” DLL importers and exporters based upon the C++ SDK can no longer be used. (The interfaces were removed!)

@thomthom, can you confirm ?

Note that there have been deprecated warnings for over 6 years that the C++ SDK was going to be removed.

So for the new C API you’d have to create a SKP file on disk, and make a Ruby C API call to Sketchup::Model#import and then likely explode the instance as it’d be loaded as a definition. Then afterward remove the imported definition.

The issue is not just with custom attributes … it is the fact that it is a closed source feature, which might be changed, abandoned or replaced with another system in the future.

Generally, … they are slowly working on getting the C API to be able to modify a “live” model.
But at this time, the C API is read-only (for a “live” model object) !

The DC attributes are settable / modifiable from the Ruby API at this time, and so can be from C using Ruby’s C API calls (ie, rb_eval_string, rb_funcall, etc.)

See:
Extending Ruby 1.9: Writing Extensions in C" by Dave Thomas

However, I cannot say whether the DC code will continue to be the foremost parametric feature for SketchUp components going forward. (There are some quirky issues.)

I would think that IF Trimble wanted to enhance the Shop (for Web) platform they’d think about reimplementing the DC code in C so it could be ported to the WebAssembly/ANGLE more easily for the online edition.

And that would also mean better interoperability for the C API as well. But we do not know exactly what their future plans may be.

The xml_to_skp is using the C API, not the old C++ API.

Importers and exporters still use a C++ interface. But that is not part of the old C++ SDK we removed.

Developers do not have to make a Ruby extension.

Importers are not working on the Live C API. They create a temporary SKP which is loaded into the model once the import process is complete.

1 Like

Can you reproduce this in a small standalone example please?
And create a separate topic for each issue so it’s easier to follow the conversation.

Dynamic Components have no API exposed. There are people who have figured out how to make calls to internal methods in the Dynamic Component extension, but this is subject to change at any time. We also don’t have plans on exposing an official DC API.

From a C importer you don’t have any way to force such an update as this can only be done from within the Ruby environment.

By the way, you are leaking SUTypedValueRef objects in your SetDoubleAttribute function. Passing in a SUTypedValueRef doesn’t take owership of it - it only copies the value. You have to release all SUTypedValueRef objects you create.

2 Likes

Ah, I stand corrected. Thanx.

I will create a small example project tomorrow and post it on a new thread as requested.

Thank you for pointing this out, I must have missed this.

1 Like

I will try to set the parameters of the DC using ruby, thanks for the info!

The new thread discussing the parameter problem has been created here: Changing dynamic component parameters from importer doesn't always work

1 Like

@tt_su Is there a observer callback that triggers at the completion of the import process ?

1 Like

No explicit importer callback. But I’d think observer related to adding entities, definitions and instances to trigger - like any other geometry change.

1 Like

Okay, further, does the import process create a temporary definition ?

The importer gets a path to a tempfile to write a SKP file to, this is then loaded into the model when the importer has done its work. Don’t think there’s any temporary definitions.