Method to ask a dynamic component instance to recalc itself?

If a user manually scales any dynamic component it may respond by recalculating its internal logic.
If a ruby script scales such a component, no refresh is triggered.
Is there a method I can call to tell the component to recalc?

Yes, provided that the global reference is always there. (It shouldn’t really be a global and could change in the future to a class method that returns a reference to the singleton instance.)

def recalc_dc(inst)
  return nil unless defined?($dc_observers)
  if inst.is_a?(Sketchup::ComponentInstance) &&
  inst.attribute_dictionary('dynamic_attributes')
    $dc_observers.get_latest_class.redraw_with_undo(inst)
  end
  nil # (there is no particular return value)
end
3 Likes

Thanks a lot. that worked!
Another question:

I haven’t created any dynamic components so don’t fully understand all the possibilities.
But I’ve used several that respond to scaling.
Is it likely than any dynamic components would need a recalc after a translate or rotate?
I can easily add your method for those cases also.

I would say it depends upon whether the origin or rotational properties are used within any other dc attribute formulas.

It probably wouldn’t hurt.

But the DC extension’s own observers are supposed to detect instance changes and do a redraw. Seems like there might be a DC bug with scaling. (Check the thread I started on DC errors in this category.)

Hi Dan,

I’ve just had my new extension rejected by the extension warehouse tester because:
“ERROR: New global variables: 1
$dc_observers”

I assume that this is NOT a new global variable, but one that already exists by virtue of the dynamic component extension. Can you tell me what the status of this variable is for Sketchup16.

:

Yes, true, you are correct.

(1) It still exists.
(2) It itself is poor practice, and could have been a class variable reference (implemented in a singleton manner.) It could have been exposed via a class constant or a class getter method.
(3) As I said above, It might not exist in future versions, if they re-implement it’s reference per (2).

So, you’ll need to do a object search and hold a local reference inside your module, to the same singleton object that $dc_observers is also referencing.

def recalc_dc(inst)
  return nil unless defined?(DCObservers)
  if inst.is_a?(Sketchup::ComponentInstance) &&
  inst.attribute_dictionary('dynamic_attributes')
    if @dc_observers.nil?
      ObjectSpace.each_object(DCObservers) {|o| break @dc_observers = o }
    end
    return nil unless @dc_observers.respond_to?(:get_latest_class)
    latest_dc_class = @dc_observers.get_latest_class
    return nil unless latest_dc_class.respond_to?(:redraw_with_undo)
    latest_dc_class.redraw_with_undo(inst)
  end
  nil # (there is no particular return value)
end

But, since the DC extension is Trimble’s extension, there is still no guarantee they’ll approve your extension.

Other way to fool an automated check:

return nil unless global_variables.map{|v|v.to_s[1..-1]}.include?("dc_observers")

It I insert this as second line of your original method, what do I do to avoid the $ in line 5?

my_dc_ob = global_variables.map{|v| v if v =~ /dc_observers/}.compact[0]

…maybe…

Clearly some checker at EWH is being over zealous.
$dc_observers
IS made by them
Others like $: are also used widely.
they cannot really expect to stop all scripts using those.

They should have a list of the common $ globals which any developer might reasonably expect to [re]use in their own code.
So rather than seeking a workaround I suggest you appeal to common sense and ask them to reconsider.
Surely they must have a list ???
Otherwise they should not even allow their own DC tool’s code to be distributed because it uses $ globals !

You don’t, Barry. You use the updated method I posted in post:
http://forums.sketchup.com/t/method-to-ask-a-dynamic-component-instance-to-recalc-itself/13905/6

The global_variables() method returns an array of string names in Ruby 1.8, and an array of symbol names in Ruby 1.9+. It does not return actual references to objects. You’d need to pass any name through to_s() then eval() it within TOPLEVEL_BINDING.

The map() method is likely not the one to use, perhaps the find() or find_all() filters instead (which would avoid the need to use compact().

@dc_is_loaded = global_variables.find{|v| v =~ /dc_observers/} ? true : false

… would work now, but fail in the future if the DC extension properly switched to an internal singleton reference for the DCObservers object. (Actually it should have been a module instead of a class, and could still be changed to a module. But perhaps they did not want anyone using it as a mixin library?)

So, I found it simpler to just test for the class identifier, to determine if the DC extension is loaded:

@dc_is_loaded = defined?(DCObservers) ? true : false

or

return nil unless defined?(DCObservers)

Then in order to avoid even using an eval("$dc_observers") string that has a dollar sign character, I opted to use the ObjectSpace iterator, and specifically look for the first object of class DCObservers.

ObjectSpace.each_object(DCObservers) {|o| break @dc_observers = o }

The checker “robot” sends a message from a NOREPLY email address. So I’ve appealed to Chris Fullmer’s common sense but still have no reply. If you are curious, the Extension is called “2DXY SlickMoves”. Demo video at 2DXY SlickMoves Demonstration - YouTube

Do you know any SketchUp user who wouldn’t want this?

1 Like

Post Script: My extension “2DXY SlickMoves”, after the SketchUp testers reviewed these posts, was approved without modification and is live on the extension warehouse. For all those who helped me on this forum on several topics over the last 6 month: Send me a PM and I will give you a free license.

1 Like

Hello All,
I also have a question related to this discussion: did anyone encounter a warning/confirmation message box saying something like:
when extension attempts to perform redraw of a dynamic component from ruby?
Refreshing takes place as expected after answering “Yes” and then no warnings appear for some time. Then the same warning may appear again.
I wonder is it possible to suppress this message or maybe it is possible to set greater redraw time limit?

That is part of the DC extension, and the settings are not public. But I do have a “shoehorn” way of changing them (somewhere.) The settings really should have had an interface from the start, or at least a class method so someone could create their own interface. There was an old thread about this on SketchUcation. (I’m thinking maybe 5 years ago?)

1 Like

Hi Dan, thanks! I’ll try to search SketchUcation forums.

I am pretty sure Sketchup did not develop dynamic components, they purchased it from one of the community members. B)

That would come as surpise to Scott !
I believe it was co-developed in-house for SketchUp by their team - mainly Scott Lininger [and Scott Shattuck?].
That was back in the days before Trimble, and perhaps even Google.
Scott no longer works for SketchUp.
https://blog.sketchup.com/authors/scott-lininger

3 Likes

That’s a great pity! I guess it implies that some of the long-standing bugs in DC will never be fixed, and some of the oh-so-needed features will never happen either. It seems to me that there’s not much interest at all from Trimble in updating or improving DC. So we are stuck with it, exactly the way it is, I guess. Warts and all!

I understand that @thomthom was charged with making some changes to DCs…
But since the team also has dozens more fish to fry it’s probably not a priority ??