Component instance point when importing model

With my plugin I am grabbing a components instances and getting those points.

  instances = comp.instances
  # Create a points array to hold all the coordinates for each instance
  pts = []

  # Loop through each instances and save the coordinates
  instances.each { |inst|
      point = inst.transformation.origin
      px = point.x
      py = point.y
      pz = point.z
      pts.push (point)
  }#instances.each 

Then I am using those points to swap that component with another. Everything works well and the components swap at the correct point. The only issue I am having is if I save out the component. Then I open a new sketchup file and I drag my saved skp file into my new model. Say the original saved component was placed at the origin, and I drag it into the new model and place it anywhere but the origin. When I am going to get the point, I do not get the new point, I get the origin.
Once I explode the imported component it picks up the new point, but still remembers the origin point. So when I go to swap the component it swaps at the new point and the origin.
How can I work around this behavior?

Why do you have to do it this way ?
Let’s say that you have a reference to that alternative component-definition ‘defn
Then you can use:

instances.each { |inst|
      inst.definition = defn
}

It’s swapped without recourse to finding its insertion point etc…

You need to swap the whole component or just an entity inside him?


I am placing components in the model like the picture above. It is in a “model” mode. Then I have a button the user can press to preview what that “model” looks like(It’s just a simple billboarding model, basically a rectangle with a texture on it). Which is the second picture. I am hiding the components in the top picture and placing their matching “texture” mode components where they are in the scene.

The user can not move or edit the “texture” mode component. But they can move the “model” mode. If they edit the “model” mode, like move the guy on the right forward some, and then go back to the preview “texture” mode, it updates the position accordingly.

Everything works great when they are placing the components in the model. Its when I save out the guys and then try to import the model into a new model that I lose this ability.

So I saved the model in the images above, and below is after I dragged that model into a new skp file. I drop them away from the origin.

But when I go to toggle between my modes they remember the old points.

If I explode them, I get this behavior:

I hope the images explain better what I am trying to accomplish.

Alright, what is the code when pressing your button to toggle between mode’s?

    # Create array to hold Model Mesh components
    m_components = []
    # Create array to hold Preview Texture components
    p_components = []

    #Go through each component checking the attributes 
    definitions.each { |d| 
      if d.attribute_dictionaries
          mValue = d.get_attribute("A", "PreviewMode")
          preValue = d.get_attribute("A", "PreviewId")
          #If the model component has a PreviewMode attached add it to the m_component array
          if (mValue != nil)
            m_components.push(d)
          end#if
          #If the component is a preview component, add it to the p_component array
          if (preValue != nil)
            p_components.push(d)
          end#if        
      end#if
    }# definitions.each

When I create my components I add a “PreviewMode” attribute to the “model” components(They also have an ID that I give them, but I don’t need that at this part). When I create the “model” component, I also create a matching preview component that goes with it, but I do not use it until the mode is toggled. I loop through the definitions and find all the components I need to perform the toggle. I then loop through all the m_components and get each position in the model.

    m_components.each { |comp|
      
      instances = comp.instances
      pts = []

      instances.each { |inst|
          inst.layer = rpcLayer
          point = inst.transformation.origin
          px = point.x
          py = point.y
          pz = point.z
          pts.push (point)
      }#instances.each 

      # Set the index location for the array to the beginning
      indexLocation = 0
      savedIndex = nil

      #Get the ID and store it in "tempID"
      if comp.attribute_dictionaries
        v = comp.get_attribute("A", "ID")
        tempID = v     
      end#if

      #Loop through the Preview Components to find the ID that
      #  matches the model component "tempID"
      p_components.each {|preComp|
          if preComp.attribute_dictionaries
            pID = preComp.get_attribute("A", "PreviewId")
            if (pID == tempID)
              # When a match is found save the location in the p_components array to
              #   grab that component for the swap
              savedIndex = indexLocation
            end#if
          end#if
          indexLocation = indexLocation + 1
      }#preview_components.each

      # Grab the matching component
      swapComp = p_components[savedIndex]    
        
      #Swap the preview component for the model component at each 
      #  matching instance coordinate. 
      pts.each { |pt|
          new_instance = entities.add_instance(swapComp, pt)
          #Lock the preview component instance so that the original
          #  geometry of the model component cannot be changed.
          status = new_instance.locked = true
      }#pts.each
    }#m_components.each

FYI, the attribute_dictionaries collection is shared by all extensions. It may not be good to use simple dictionary names that other extensions might also use. (Name clash)

It is good practice to prefix your dictionary name with author name and plugin name. Often you can use the qualification of the encapsulating modules.
DICT = ECW_Peoplifier_A
or more plyable (allowing outer modules to be renamed at will):
DICT = Module::nesting[0].name.gsub('::','_')

Using a constant in your get_attribute calls is better, more easily maintained, and uses less string memory space. (You’re using multiple literal string objects that could share a single string object.)

I do use more unique names for my attribute_dictionaries, I just change/simplify all my variables when posting on this forum.

1 Like