Make unique, a manually placed component

Hello everyone!

I want to make unique, all the components added and placed manually with the tool moved.

      mod = Sketchup.active_model
      path = Sketchup.find_support_file("MyComponent.skp",
       "Plugins/plugin folder/subfolder/"
      )
      Component = mod.import(path) 
 	

As the method is executed before positioning the furniture, I find no solution.

Information

If the component is loaded with a defined position in the method, all become possible.

          mod = Sketchup.active_model
          entities = model.active_entities
          defs = mod.definitions
          path = Sketchup.find_support_file("CLICK-CUISINE 2 - MB RGT_04.skp", 
           "Plugins/TNT_ClickCuisine2/Components/"
          )
          definition = defs.load(path)
          point = Geom::Point3d.new(0, 0, 0)
          transformation = Geom::Transformation.new(point) 
          instance = entities.add_instance(definition, transformation)
          instance.make_unique

My goal is to be able to do a “grep”, of the component placed with the cursor of the mouse.

If that’s possible, then I could make it unique and do a lot more.

Thank you in advance for your help.

David

For the 4th time, will you please read this sticky post and apply it when posting code here in the forum !

… so that your code is properly lexed like:

  mod = Sketchup.active_model
  path = Sketchup.find_support_file("MyComponent.skp", "Plugins/plugin folder/subfolder/")
  component = mod.import(path)

(Notice that I changed the constant reference "Component" to the local variable reference "component" !)

Also, it is better forum code etiquette if readers do not need to scroll horizontally to read your code. So please wrap argument lists in method calls like:

  mod = Sketchup.active_model
  path = Sketchup.find_support_file(
    "MyComponent.skp", "Plugins/plugin folder/subfolder/"
  )
  component = mod.import(path)

I think then you need to be using model.place_component()

Also instance#make_unique does not return Boolean (true or false).
It returns a reference to a component instance. But the docs are unclear whether it is implemented the same as group#make_unique.

I have filed an API documentation issue on this ambiguity:

The problem is exactly the same with the “place_component” method.

  mod = Sketchup.active_model
  defs = mod.definitions
  path = Sketchup.find_support_file("MyComponent.skp", 
   "Plugins/plugin folder/subfolder/"
  )
  import = defs.load(path)
  mod.place_component(import)

ps : I corrected my post by applying the colors.

definition = defs.load(path)
before = definition.instances
# place the instances
placed = definition.instances - before # array subtraction

OR… you also can save references to each instance as you add them to the entities …

placed = []
# loop where instances are placed according to points:
points = [[0,0,0],[1,2,3],[3,4,5]]
for point in points
  transformation = Geom::Transformation.new(point) 
  placed << entities.add_instance(definition, transformation)
end

… then do your unique-ifying:

placed.each {|i| i.make_unique }

import.instances[-1].make_unique

john

John for your solution to work I must execute the import code.

Then run a second method to make the last imported instance unique.

This is not the goal, if not, it would be too easy. :yum:

The bute is all to do at the same time!

I want to write a method, which imports the furniture and makes it unique in the same code execution.

I imagine that the method’s reading should pause for the user to place the piece of furniture, then resume performing to make it unique?

This Dan solution returns an empty array [] because the before variable is not found until the user has placed the component in SketchUp.

This second solution loads the components 3 times on the stage with different positions defined by your points variable.

Thanks anyway.

David

the user may also want to fine tune it’s position, before interacting with it…

change the path and try this…

mod = Sketchup.active_model
defs = mod.definitions
path = '/Users/johns_iMac/Library/Application Support/SketchUp 2018/SketchUp/Components/tests/cube2.skp'

import = defs.load(path)

mod.place_component(import)

# after placing the comp the user may want to manipulate it using these tools
modifiers = ['ComponentTool', 'MoveTool', 'ScaleTool', 'RotateTool', 'OrbitTool', 'DollyTool' ]
names = Regexp.union(modifiers)
# this is just for reporting
@tool = ''
# we start a timer
what_comes_next = UI.start_timer(1.0, true) do
  # that waits till the user tries to do soemthing else
  if Sketchup.active_model.tools.active_tool_name =~ names
    #
    tool = Sketchup.active_model.tools.active_tool_name
    p tool if tool != @tool
    @tool = tool
  else # this is before the 'pop' back
    defn = import
    ins = defn.instances
    len = ins.length.freeze
    if len > 1
     ins.each do|i|
       i.make_unique
     end
    end
    # we can activate interact here if we want
    Sketchup.active_model.select_tool(DCInteractTool.new($dc_observers))
    p 'rename done'
    UI.stop_timer(what_comes_next)
  end # if tool
end # what_comes_next

john

I found the solution to my problem!

Here is the code:

  mod = Sketchup.active_model
  entities = mod.active_entities
  defs = mod.definitions
  definitions = Sketchup.find_support_file("CLICK-CUISINE 2 - MB RGT_04.skp", 
    "Plugins/TNT_ClickCuisine2/Components/"
  )
  definition = defs.load(definitions)
    mod.definitions.each do |d| 
      d.instances.each do |i|
        i.make_unique
        mod.place_component(definition)
      end
    end

Thanks for your help.

David

Thank you for your method John but the result is “nil”.

Warning!
Your method to an end in excess.

As long as a component is not physically placed by the user, it is inaccessible by the code.

Even my solution makes all instances of SketchUp unique, and has no way to access the component that needs to be imported and placed.

I think there is simply no solution to the problem.

Thank you for your support.

what do mean?

in your first post you said…

this is what my snippet does…

uniq_comp

that’s why you have to wait for it to be placed…

john

John in your example, the component becomes unique when you make a manual transformation.

The first cube makes you a rotation and for the second a scaling.

The bottom line is that the cube is made unique at the time of insertion and not after a transformation.

Cordially

David

try this…

# just use a single modifier
modifier = ['ComponentTool']
#and comment out the DC tool latter in the code
  # Sketchup.active_model.select_tool(DCInteractTool.new($dc_observers))

when it’s placed it becomes unique…

john

You misunderstand. I did not (and will not) give complete solutions for development of a paid extension. Meaning, I will NOT do YOUR work FOR you.

I was giving examples that related to basic coding principles having to do with what I thought you wanted. I was hoping you will take some ideas and figure out the solution YOURSELF. This is the only way you will learn programming.

But your questions are not clear! It took you until the 7th post in the thread to finally state what you wanted …

The interactive mouse placing methods of the API, do NOT stop and wait. (This has already been discussed here in the forum. Search!)

To work with instances after placing, … you most likely need to implement a DefinitionObserver with a onComponentInstanceAdded callback method. You’ll need to attach the observer just before calling the place code, and detach it as soon as it’s no longer needed.

Do a forum search on “place_component” you’ll find some examples.

I’m not asking you to do my job, I’m just waiting to be put in the right direction.

In addition I also develop free extensions like Click-Change!
Dailleur Click-Change 2, is final phase and will be as Free as version 1.

I totally agree with you about that.

I did everything to be as accurate as possible from my first publication, so I do not agree!

Just the title of the topic is enough to understand!

Thank you for confirming what I thought.

I will look in this direction hoping to reach a solution.

I’m thinking this risks targeting a nested group or component. Can we be sure the top level placed component is actually the last in the definition list?

it’s targeting only the named definition instances, rather than the full definitions list…

it could fail if the user also moves copies, which is why my working example checks for those as well…

    defn = import
    ins = defn.instances
    len = ins.length.freeze
    if len > 1
     ins.each do |i|
       i.make_unique
     end

john

So you want to make unique each component instance placed by the user, for specific component definitions?
The first thing that comes up to me is using an observer on each definition you wish to have this behaviour on.

    # This is an example of an observer that watches a specific definition
    # for new component insertions.
    class MyDefObserver < Sketchup::DefinitionObserver
      def onComponentInstanceAdded(definition, instance)
        puts "onComponentInstanceAdded(#{definition}, #{instance})"
      end
    end

    # Attach the observer
    Sketchup.active_model.definitions[0].add_observer(MyDefObserver.new)

So, in the callback you could make the new instance unique. However, by doing so, you are generating a new component definiion, which you probably also want to attach this very same observer to.

Hello Kengey .
Your analysis is right!
I found all the answers to my questions about observers in this topic:


cordially
David