Recommended method to handle push-pull geometry modifications

Hey folks,

Apologies if I’m resurfacing on old topic.

I’m running into issue with my render plugin for SketchUp when push-pulling faces:

The root of the issue is that the SketchUp API only sends an onElementModified event for the face that’s being pushed or pulled, but not for its adjacent faces. This was discussed before in this forum post.

I have 2 questions:

  • In this forum post, @tt_su opened a feature request regarding this (SU-38061). Where can I lookup feature request SU-38061?
  • What is the recommended way to handle push-pull operations in a plugin? I could for every face look at the adjacent faces and update them as well, but that might result in performance issues. Is there a way to detect if the operation is a push-pull and only do this in that case (preferably directly in the live C-extension API).

Regards,
Thomas

You cannot. It is an issue number in the SketchUp Team’s internal issue database.

You could possibly use the ToolsObserver to detect that the active_tool_id is the PushPull tool’s id.

The C API does not have observers, but you could have a Ruby observer call a C function that gathers entity properties and passes the data to your renderer.

FYI, Ruby itself is implemented in C, so Ruby has a C API (aka ABI.) For more information you can download this book:

Extending Ruby 1.9: Writing Extensions in C
by Dave Thomas
** PDF
https://media.pragprog.com/titles/ruby3/ext_ruby.pdf

2 Likes

Ruby programming is multi-paradigm. There are possibly several ways.

(1) Perhaps use a combination observer that implements ModelObserver#onActivePathChanged to detect when the user enters a nested edit context, then attach a EntityObserver that implements #onChangeEntity to each Entity member of the Entities collection being edited.

But this also has a weakness as new Drawingelements that the operation creates will not have observers attached and might get missed. So you may also need to still implement EntitiesObsever#onElementAdded to attach the observer to new things as they are created.

(2) Another coding pattern often used is the “snapshot” pattern. Your code takes a “snapshot” array of the Entities:

before = ents.to_a

… then the operation is performed, and you subtract the “before snapshot” array from the array taken afterward:

new_stuff = ents.to_a - before

REF: Array#-

Also, beware of deleted entity references after editing operations. Remove non valid entity references:

array_of_stuff.delete_if(&:deleted?)

Thanks @DanRathbun for the very detailed advice.

I’m going to try to implement it using method (1) - Implementing via observers, instead of via the snapshot pattern, because observers is the pattern I have been following so far. Combining this with the ToolsObserver seems like a promising strategy for success.

Will report back how it goes.

Regards,
Thomas

Thanks again for the advice!

The combination of EntitiesObserver and tracking if the push-pull tool is active when a face is modified solves the issue for me. Now the push-pull is successfully propagating to my extension.

rayscaper-push-pull-fixed

1 Like